以下のようなテーブルのとき
CREATE TABLE foo ( aset set('aaa', 'bbb', 'ccc') );
- 空文字列を SET のメンバーとして許していない
- null 可
値を追加する
UPDATE foo SET `aset` = CONCAT_WS(',', NULLIF(aset, ''), #{member});
aset が空文字列(emptyset)のとき、これをそのままカンマで CONCAT_WS すると、",ccc" とかになり、空文字列のメンバーは許容していないため data truncated でエラーになってしまう。
CONCAT_WS は引数が null のときはそれを飛ばして連結するので、それを利用する。
ref. https://stackoverflow.com/questions/14642658/the-best-way-to-remove-value-from-set-field
値を削除する
UPDATE foo SET `aset` = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', aset, ','), CONCAT(',', #{member}, ','), ','))
もっとややこしい。というのも ",aaa" も "aaa,,ccc" も "aaa," も不正なので、こういう値にならないようにしないといけない。
備考
SET は実際は 64bit の数値なので、SET のメンバー名(文字列)を2の乗数の数値に変換する方法があれば、単にビット演算ですむ。けど、MySQL 上にはこの方法 (メンバー名を SET の数値に直接変換する) がない(と思う)。アプリケーション側で数値と文字列のマッピングを持てば SQL は簡単になるが DDL と常に整合性をとる必要があってややこしく、それなら SET じゃなく BIGINT UNSIGNED で持てばいいことになる。
なんかいい方法あったら教えてください (SET 使うな以外で)