Reputation: 3717
Say I have student
table with a column name
.
This name
column has values 'studentone', 'studenttwo', 'studentthree'
& I want to replace them with 'student1', 'student2', 'student3'.
For single replacement it's quite straight forward:
update student set name = replace(name, 'one', '1')
But what about multiple replacements? Any idea?
Upvotes: 7
Views: 14778
Reputation: 657912
replace()
While you could pack all into one statement, it would be inefficient without a matching WHERE
condition to exclude unaffected rows. It's expensive nonsense to update rows that don't actually change. See:
UPDATE student SET name = replace(name, 'one', '1') WHERE name LIKE '%one';
UPDATE student SET name = replace(name, 'two', '2') WHERE name LIKE '%two';
UPDATE student SET name = replace(name, 'three', '3') WHERE name LIKE '%three';
This only finds and updates rows that actually change. Matching the end of the string according to your example.
The most efficient way would be to combine that with something like @Bohemian suggested:
UPDATE student
SET name = replace(replace(replace(
name
, 'one' , '1')
, 'two' , '2')
, 'three', '3')
WHERE name ~ '(one|two|three)$';
But make sure that one replacement does not influence the next.
Actually, a couple of OR'ed LIKE
expressions are typically faster than a single regular expression, so:
WHERE (name LIKE '%one' OR
name LIKE '%two' OR
name LIKE '%three');
CASE
Another possibility (as suggested in a comment):
SET name = CASE WHEN name LIKE '%one' THEN replace(name, 'one', '1')
WHEN name LIKE '%two' THEN replace(name, 'two', '2')
WHEN name LIKE '%three' THEN replace(name, 'three', '3')
ELSE name
END
The ELSE
clause is just an optional insurance in this case. Since our WHERE
clause excludes rows that wouldn't change, control never reaches ELSE
. (Without spelling out ELSE
, the expression would default to null
in this case.)
Depending on exact circumstances, this might be optimized. For your example:
SET name = CASE right(name, -7)
WHEN 'one' THEN student || '1'
WHEN 'two' THEN student || '2'
WHEN 'three' THEN student || '3'
ELSE name
END
Upvotes: 4
Reputation: 2676
There is a prebuilt function here for replacing multiple strings in one go, using a JSON dictionary format for the input, e.g.:
select multi_replace('foo and bar is not foobar',
'{"bar":"foo", "foo":"bar", "foobar":"foobar"}'::jsonb);
https://wiki.postgresql.org/wiki/Multi_Replace_plpgsql
Upvotes: 0
Reputation: 425198
I would just use multiple update statements, but if you absolutely must do it in one statement, just nest the replace calls:
update student set
name = replace(replace(replace(name, 'one', '1'), 'two', '2'), 'three', '3')
This works because (although inefficient) calls to replace()
have no effect if the search term is not found.
Upvotes: 7