ikasama over technology

忘れたくないことを忘れないために

MySQL で split, join したいとき

素の SQL で DB にパッチをあてる運用とかがあると*1、こんなことがあります。

  • SQL の条件に変数を使いたい
mysql> SELECT * FROM test;
+----+------+
| id | name |
+----+------+
|  1 | hoge |
|  2 | fuga |
|  3 | foo  |
|  4 | bar  |
+----+------+
4 rows in set (0.00 sec)

mysql> SELECT * FROM test WHERE name IN ('hoge', 'fuga');   # ←ここの IN の中とか!
+----+------+
| id | name |
+----+------+
|  1 | hoge |
|  2 | fuga |
+----+------+
2 rows in set (0.00 sec)
  • でも MySQL の変数は複数の値を持てない
mysql> SET @names = ('hoge', 'fuga');
ERROR 1241 (21000): Operand should contain 1 column(s)
  • そうだ、join して split しよう! ←いまここ

MySQLjoin, split はあるのか

join

  • CONCAT_WS を使います

https://dev.mysql.com/doc/refman/5.6/ja/string-functions.html#function_concat-ws

mysql> SELECT CONCAT_WS(',', 'hoge', 'fuga');
+--------------------------------+
| CONCAT_WS(',', 'hoge', 'fuga') |
+--------------------------------+
| hoge,fuga                      |
+--------------------------------+
1 row in set (0.00 sec)

split

  • 残念ながら、MySQL には split に相当する機能はないです
  • ただし、検索条件として使うなら FIND_IN_SET で代替できます
    • FIND_IN_SET の第二引数はカンマ区切りである必要があります
    • データにカンマが含まれているからパイプで繋いでたりしてるとアウトです、あきらめましょう

https://dev.mysql.com/doc/refman/5.6/ja/string-functions.html#function_find-in-set

mysql> SELECT FIND_IN_SET('fuga', 'hoge,fuga');
+----------------------------------+
| FIND_IN_SET('fuga', 'hoge,fuga') |
+----------------------------------+
|                                2 |
+----------------------------------+
1 row in set (0.00 sec)

mysql> SELECT FIND_IN_SET('foo', 'hoge,fuga');
+---------------------------------+
| FIND_IN_SET('foo', 'hoge,fuga') |
+---------------------------------+
|                               0 |
+---------------------------------+
1 row in set (0.00 sec)

これらを組み合わせて

mysql> SET @names = CONCAT_WS(',', 'hoge', 'fuga');
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @names;
+-----------+
| @names    |
+-----------+
| hoge,fuga |
+-----------+
1 row in set (0.00 sec)

mysql> SELECT * FROM test WHERE FIND_IN_SET(name, @names);
+----+------+
| id | name |
+----+------+
|  1 | hoge |
|  2 | fuga |
+----+------+
2 rows in set (0.00 sec)

できた!

*1:弊社です