正直、このSELECTは必要ない。SELECTしなくても上手く更新できる。
例として次のテーブルとデータを考えよう。
CREATE TABLE `person` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`attribute` set('ツンデレ','ツインテール','眼鏡','貧乳','双子') NOT NULL,
PRIMARY KEY (`id`)
);
mysql> select * from person;
+----+-----------+----------------------------------------+
| id | name | attribute |
+----+-----------+----------------------------------------+
| 1 | こなた | 貧乳 |
| 2 | かがみ | ツンデレ,ツインテール,双子 |
| 3 | みゆき | 眼鏡 |
| 4 | つかさ | 貧乳,双子 |
+----+-----------+----------------------------------------+
まずは追加を考える。全員がツインテールにしたとしよう。もちろん他の属性要素はそのまま残る。どう更新するか。mysql> update person set attribute = concat(attribute, ',ツインテール');
Query OK, 3 rows affected (0.00 sec)
Rows matched: 4 Changed: 3 Warnings: 0
mysql> select * from person;
+----+-----------+----------------------------------------+
| id | name | attribute |
+----+-----------+----------------------------------------+
| 1 | こなた | ツインテール,貧乳 |
| 2 | かがみ | ツンデレ,ツインテール,双子 |
| 3 | みゆき | ツインテール,眼鏡 |
| 4 | つかさ | ツインテール,貧乳,双子 |
+----+-----------+----------------------------------------+
set型は要素の順番は関係ないので、concat関数で最後にツインテールという要素をつなげてやれば上手く更新できる。同じ要素が入っていても良いので元からツインテールのかがみも問題無し。要素の前にカンマを入れるのがポイント。引用元
SET 要素を複数持つ値では、値の挿入時には、要素を列記する順序は重要ではありません。値の中で特定の要素を列記する回数も重要ではありません。 その後、値を取り出すときには、値内の各要素は 1 回のみ出現し、テーブルの作成時に指定された順序でそれぞれの要素が列記されます。たとえば、カラムが SET("a","b","c","d") として指定されている場合、このカラムの値を取り出したときには、"a,d"、"d,a"、"d,a,a,d,d" はいずれも "a,d" として表現されます。
追加は文字列関数でなんとかできた。削除もreplace関数で文字列を除去すればできるように思える。
mysql> update person set attribute = replace(attribute, '双子', '');
Query OK, 2 rows affected, 2 warnings (0.00 sec)
Rows matched: 4 Changed: 2 Warnings: 2
mysql> select * from person;
+----+-----------+---------------------------------+
| id | name | attribute |
+----+-----------+---------------------------------+
| 1 | こなた | ツインテール,貧乳 |
| 2 | かがみ | ツンデレ,ツインテール |
| 3 | みゆき | ツインテール,眼鏡 |
| 4 | つかさ | ツインテール,貧乳 |
+----+-----------+---------------------------------+
しかし、これはあくまで文字列の削除なので、双子座と言う要素があった場合は、双子だけでなく、双子座も要素から外れてしまう。仮に要素を上手いこと問題なく設定していたとしても複数削除の場合は、replace関数を入れ子にしてやる必要があるので記述が手間である。不可能ではないかもしれないが、set型を文字列として扱い、文字列関数で上手く更新するのは難しそうだ。どのように扱えば良いかは、また今度。