以下のようなテーブルのとき

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 使うな以外で)

  1. トップ
  2. tech
  3. MySQL で SET 型の UPDATE