2011年2月17日木曜日

MySQL set型 要素取り出す?

ウェブマスター ツールを見てると「MySQL set型 要素取り出す」というクエリで先日書いたmysql set型 その1の記事へのアクセスがあった。MySQL set型の要素を取り出すとはどういうことだろう?と、思いちょっと考えてみる。

テーブルは先日のものを流用して下記とする。
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 | つかさ    | 貧乳,双子                              | 
+----+-----------+----------------------------------------+
0. set型カラムに設定してある要素を取り出したい。
これは、普通にselectしてやれば、設定されてる要素は取り出せるし、調べるようなことではないから違うだろう。

1. set型カラムに定義してある全ての要素を取り出したい。
これは、descやshow fields使ってやればとれる。show fieldsなら必要なカラムを指定することもできる。Typeに型定義の要素があるので、それを使えば良い。
mysql> desc person;
+-----------+---------------------------------------------------------------------+------+-----+---------+----------------+
| Field     | Type                                                                | Null | Key | Default | Extra          |
+-----------+---------------------------------------------------------------------+------+-----+---------+----------------+
| id        | int(11)                                                             | NO   | PRI | NULL    | auto_increment | 
| name      | varchar(32)                                                         | NO   |     | NULL    |                | 
| attribute | set('ツンデレ','ツインテール','眼鏡','貧乳','双子')                 | NO   |     | NULL    |                | 
+-----------+---------------------------------------------------------------------+------+-----+---------+----------------+

mysql> show fields from person;
+-----------+---------------------------------------------------------------------+------+-----+---------+----------------+
| Field     | Type                                                                | Null | Key | Default | Extra          |
+-----------+---------------------------------------------------------------------+------+-----+---------+----------------+
| id        | int(11)                                                             | NO   | PRI | NULL    | auto_increment | 
| name      | varchar(32)                                                         | NO   |     | NULL    |                | 
| attribute | set('ツンデレ','ツインテール','眼鏡','貧乳','双子')                 | NO   |     | NULL    |                | 
+-----------+---------------------------------------------------------------------+------+-----+---------+----------------+

mysql> show fields from person like 'attribute';
+-----------+---------------------------------------------------------------------+------+-----+---------+-------+
| Field     | Type                                                                | Null | Key | Default | Extra |
+-----------+---------------------------------------------------------------------+------+-----+---------+-------+
| attribute | set('ツンデレ','ツインテール','眼鏡','貧乳','双子')                 | NO   |     | NULL    |       | 
+-----------+---------------------------------------------------------------------+------+-----+---------+-------+

2. set型カラムに特定の要素が設定してあるレコードを取り出したい。
これだとしたら、find_in_set関数を使ってやれば良い。先日も書いた通り、set型は数値としても扱えるのでビット演算でも抽出できる。ただ、set型らしいのはfind_in_setだろうと思う。ビット演算では何を対象としたかったのかがSQLだけでは読み取れなくなってしまうので。
mysql> select name, attribute from person where find_in_set('貧乳',attribute);
+-----------+---------------+
| name      | attribute     |
+-----------+---------------+
| こなた    | 貧乳          | 
| つかさ    | 貧乳,双子     | 
+-----------+---------------+

mysql> select name, attribute from person where attribute & 8;
+-----------+---------------+
| name      | attribute     |
+-----------+---------------+
| こなた    | 貧乳          | 
| つかさ    | 貧乳,双子     | 
+-----------+---------------+

3. set型カラムに設定してある特定の要素だけを取り出したい。
これだとしたら、少し面倒だ。と、言うかかなり強引なやり方に思える。2でwhere句にあったものをselect句内のif式に持ってきて、その要素を持ってるレコードでは、その要素とし、ないものを空とする。
mysql> select name, if(find_in_set('貧乳',attribute),'貧乳', '') from person;
+-----------+--------------------------------------------------+
| name      | if(find_in_set('貧乳',attribute),'貧乳', '')     |
+-----------+--------------------------------------------------+
| こなた    | 貧乳                                             | 
| かがみ    |                                                  | 
| みゆき    |                                                  | 
| つかさ    | 貧乳                                             | 
+-----------+--------------------------------------------------+

mysql> select name, if(attribute & 8, '貧乳', '') from person;
+-----------+---------------------------------+
| name      | if(attribute & 8, '貧乳', '')   |
+-----------+---------------------------------+
| こなた    | 貧乳                            | 
| かがみ    |                                 | 
| みゆき    |                                 | 
| つかさ    | 貧乳                            | 
+-----------+---------------------------------+
この方法だと、複数要素だった場合はどうするんだ?という疑問も残る。MySQL側ではやらずに、普通にattributeをselectしてきて、アプリケーション側で不要な要素を省くという処理をした方が良いのかもしれない。

以上、ウェブマスター ツールのクエリ「MySQL set型 要素取り出す」について考察してみた。