Reputation: 1115
Which is the best way to update a mysql SET field, to remove a specific value from the field.
Eg. field categories with values: 1,2,3,4,5? I want to remove '2' from the list:
UPDATE table
SET categories = REPLACE(categories, ',2,', ',')
WHERE field LIKE '%,2,%';
But what if '2' is the first or the last value from the list?
UPDATE table
SET categories = REPLACE(categories, '2,', '')
WHERE field LIKE '2,%';
UPDATE table
SET categories = REPLACE(categories, ',2', '')
WHERE field LIKE ',2%';
How could I handle all 3 cases with one single query?!
Upvotes: 25
Views: 16452
Reputation: 1776
Try this to add or remove value(multiple occurrences) from your field, you may remove NULLIF & COALESCE if your field have default value as not null:
Mysql:
NULLIF(TRIM(BOTH ',' FROM REPLACE(CONCAT(REPLACE(CONCAT(',',REPLACE(COALESCE('20,21,22',''), ',', ',,'),','),',20,', ''),',30,'),',,', ',')),'') --- add 30 & remove 20
NULLIF(TRIM(BOTH ',' FROM REPLACE(CONCAT(REPLACE(CONCAT(',',REPLACE(COALESCE('20,21,22',''), ',', ',,'),','),'', ''),',30,'),',,', ',')),'') --- to just add 30
NULLIF(TRIM(BOTH ',' FROM REPLACE(CONCAT(REPLACE(CONCAT(',',REPLACE(COALESCE('20,20,21,22',''), ',', ',,'),','),',20,', ''),''),',,', ',')),'') --- to just remove 20
Upvotes: 0
Reputation: 1356
Here, the best answers have been provided by @palindrom and @JohnWoo. In fact the answer provided by @palindrom is exceptionally good and should be the accepted answer.
But, in case of answer provided by @JohnWoo, such a large case statement is absolutely unnecessary and can be done in a much more short and neat coding. I have illustrated this below -
UPDATE my_table
-> SET categories = CASE
-> WHEN categories LIKE "2"
-> THEN REPLACE(categories,"2","")
-> WHEN categories LIKE "2%"
-> THEN REPLACE(categories,"2,","")
-> WHEN categories LIKE "%2%"
-> THEN REPLACE(categories,",2","")
-> ELSE categories
-> END;
Here, studying this post on combining two update statements is helpful. I have also provided an answer here.
Upvotes: 0
Reputation: 2722
I like this way by Kris Gielen (https://blog.krisgielen.be/archives/255):
UPDATE table SET categories =
TRIM(BOTH ',' FROM REPLACE(CONCAT(',', categories, ','),
CONCAT(',', '2', ','), ','))
WHERE ...
To add a value to the set:
UPDATE table SET categories =
CONCAT_WS(',', categories, '2')
WHERE ...
Upvotes: 2
Reputation: 4014
field categories with values: 1,2,3,4,5? I want to remove '2' from the list:
I find that using a bitwise operator to be the cleanest way. The return value of FIND_IN_SET()
returns the position of the value so you can use this calculate the bit to turn off.
UPDATE table
SET categories = CAST(categories AS UNSIGNED) & ~POW(2, FIND_IN_SET('2', categories))
WHERE FIND_IN_SET('2', categories);
Note that (categories+0)
is to force the current SET
value to an integer. You may find this is redundant, but be careful with sets that contain a lot of values. I found that the resulting maths can be wrong if you don't explicitly force the set to an integer -- you definitely don't want the wrong value when performing an operation like this.
Upvotes: 3
Reputation: 93
Here is another way of doing this:
UPDATE table
SET categories = CONCAT_WS(',',
IF(FIND_IN_SET('1', categories), '1', NULL),
-- Note that '2' is missing here!
IF(FIND_IN_SET('3', categories), '3', NULL),
IF(FIND_IN_SET('4', categories), '4', NULL),
IF(FIND_IN_SET('5', categories), '5', NULL)
);
CONCAT_WS
concatenates all its arguments (except argument 1) with the first argument (in this case ','
), if they are not NULL
.
We look for each possible value of the SET
field if the field contains it but skip the one we want to remove (2
in this case). If yes, we return that value, otherwise NULL
.
This concatenates all values of the set with ','
, skipping the one we want to delete, reconstructing a new value for the SET
field.
This of course only works, if you know all possible values of categories
, but since this is a SET
field, you know that.
Upvotes: 3
Reputation: 19121
update TABLE
set COLUMN = COLUMN & ~NUM
where COLUMN & NUM
Taken from comments section of: http://dev.mysql.com/doc/refman/5.0/en/set.html
Beware though, NUM is not the value '2' but its internal index. So if you defined the field like "set ('1,'2','3','4','5')" then the corresponding indexes of these values are (1,2,4,8,16).
Upvotes: 12
Reputation: 263843
The best way is not to save values separated by a comma on the table.
But to answer your question, you can use CASE
on this,
UPDATE table
SET categories = CASE WHEN field LIKE '%,2,%' -- In the middle
THEN REPLACE(categories, ',2,', ',')
WHEN field LIKE '2,%' -- At the beginning
THEN REPLACE(categories, '2,', '')
WHEN field LIKE '%,2' -- At the end
THEN REPLACE(categories, ',2', '')
WHEN field = '2' -- At whole
THEN ''
END
WHERE FIND_IN_SET('2', categories)
Upvotes: 5
Reputation: 49089
If the value you need to remove from the set can't be present more than once, you could use this:
UPDATE yourtable
SET
categories =
TRIM(BOTH ',' FROM REPLACE(CONCAT(',', categories, ','), ',2,', ','))
WHERE
FIND_IN_SET('2', categories)
see it working here. If the value can be present more than once, this will remove all occourences of it:
UPDATE yourtable
SET
categories =
TRIM(BOTH ',' FROM
REPLACE(
REPLACE(CONCAT(',',REPLACE(col, ',', ',,'), ','),',2,', ''), ',,', ',')
)
WHERE
FIND_IN_SET('2', categories)
Upvotes: 34