SQLのlike inについてまとめています。
SQLのlikeとinの組み合わせはSyntax Errorになる
ワイルドカードによるあいまい検索ができるlikeと複数条件を簡潔に記述できるinは、同時に使うとSyntax Errorとなります。
以下はlikeを単体で実行した例です。
mysql> select * from employees where first_name like 'A%' limit 10; +--------+------------+------------+--------------+--------+------------+ | emp_no | birth_date | first_name | last_name | gender | hire_date | +--------+------------+------------+--------------+--------+------------+ | 10006 | 1953-04-20 | Anneke | Preusig | F | 1989-06-02 | | 10033 | 1956-11-14 | Arif | Merlo | M | 1987-03-18 | | 10035 | 1953-02-08 | Alain | Chappelet | M | 1988-09-05 | | 10036 | 1959-08-10 | Adamantios | Portugali | M | 1992-01-03 | | 10039 | 1959-10-01 | Alejandro | Brender | M | 1988-01-19 | | 10059 | 1953-09-19 | Alejandro | McAlpine | F | 1991-06-26 | | 10062 | 1961-11-02 | Anoosh | Peyn | M | 1991-08-30 | | 10091 | 1955-10-04 | Amabile | Gomatam | M | 1992-11-18 | | 10094 | 1957-05-25 | Arumugam | Ossenbruggen | F | 1987-04-18 | | 10103 | 1953-11-26 | Akemi | Birch | M | 1986-12-02 | +--------+------------+------------+--------------+--------+------------+ 10 rows in set (0.00 sec)
【関連記事】
▶SQLのlikeの構文 DBMSごとの独自拡張や正規表現のパターンマッチング
likeとinを組み合わせて実行しようとすると、Syntax errorとなります。以下は、MySQLで実行した例です。
mysql> select * from employees where first_name like in ('A%', 'B%' ) limit 10; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'in ('A%', 'B%' ) limit 10' at line 1
SQLのlikeとinの組み合わせを代替する方法
# select * from employees where first_name like in ( 'A%', 'B%' ) limit 10;
上記のSQLでやりたいことは、orや正規表現で代替可能です。
orで代替する方法
パターンマッチ条件をorで接続して列挙します。シンプルな条件の場合は良いのですが、条件が多くなってくるとSQLが長くなるのが欠点と言えます。
mysql> select * from employees where first_name like 'A%' or first_name like 'B%' limit 10; +--------+------------+------------+------------+--------+------------+ | emp_no | birth_date | first_name | last_name | gender | hire_date | +--------+------------+------------+------------+--------+------------+ | 10002 | 1964-06-02 | Bezalel | Simmel | F | 1985-11-21 | | 10006 | 1953-04-20 | Anneke | Preusig | F | 1989-06-02 | | 10014 | 1956-02-12 | Berni | Genin | M | 1987-03-11 | | 10023 | 1953-09-29 | Bojan | Montemayor | F | 1989-12-17 | | 10033 | 1956-11-14 | Arif | Merlo | M | 1987-03-18 | | 10034 | 1962-12-29 | Bader | Swan | M | 1988-09-21 | | 10035 | 1953-02-08 | Alain | Chappelet | M | 1988-09-05 | | 10036 | 1959-08-10 | Adamantios | Portugali | M | 1992-01-03 | | 10039 | 1959-10-01 | Alejandro | Brender | M | 1988-01-19 | | 10049 | 1961-04-24 | Basil | Tramer | F | 1992-05-04 | +--------+------------+------------+------------+--------+------------+ 10 rows in set (0.00 sec)
正規表現(regexpなど)で代替する方法
MySQLやOracleなど、正規表現によるあいまい検索が可能なDBMSでは、like+inでやりたいことを正規表現で代替可能です。
以下は、MySQLで実行した例です。正規表現の知識は必要になりますが、比較的スッキリ記述することができます。
mysql> select * from employees where first_name regexp '^[AB].*' limit 10; +--------+------------+------------+------------+--------+------------+ | emp_no | birth_date | first_name | last_name | gender | hire_date | +--------+------------+------------+------------+--------+------------+ | 10002 | 1964-06-02 | Bezalel | Simmel | F | 1985-11-21 | | 10006 | 1953-04-20 | Anneke | Preusig | F | 1989-06-02 | | 10014 | 1956-02-12 | Berni | Genin | M | 1987-03-11 | | 10023 | 1953-09-29 | Bojan | Montemayor | F | 1989-12-17 | | 10033 | 1956-11-14 | Arif | Merlo | M | 1987-03-18 | | 10034 | 1962-12-29 | Bader | Swan | M | 1988-09-21 | | 10035 | 1953-02-08 | Alain | Chappelet | M | 1988-09-05 | | 10036 | 1959-08-10 | Adamantios | Portugali | M | 1992-01-03 | | 10039 | 1959-10-01 | Alejandro | Brender | M | 1988-01-19 | | 10049 | 1961-04-24 | Basil | Tramer | F | 1992-05-04 | +--------+------------+------------+------------+--------+------------+ 10 rows in set (0.15 sec)
複数のあいまい検索条件を正規表現で代替するサンプルコード
もう少し複雑なあいまい検索条件を正規表現で代替するサンプルを紹介しましょう。
# select * from employees where first_name like in ( '%A', 'B%' ) limit 10;
Aで終わる文字列または、Bで始まる文字列にパターンマッチしたいケース。2つの正規表現をカッコ内で|(パイプ)で区切ることで実現可能です。
mysql> select * from employees where first_name regexp '(^B.*|.*A$)' limit 10; +--------+------------+------------+-------------+--------+------------+ | emp_no | birth_date | first_name | last_name | gender | hire_date | +--------+------------+------------+-------------+--------+------------+ | 10002 | 1964-06-02 | Bezalel | Simmel | F | 1985-11-21 | | 10008 | 1958-02-19 | Saniya | Kalloufi | M | 1994-09-15 | | 10014 | 1956-02-12 | Berni | Genin | M | 1987-03-11 | | 10023 | 1953-09-29 | Bojan | Montemayor | F | 1989-12-17 | | 10034 | 1962-12-29 | Bader | Swan | M | 1988-09-21 | | 10049 | 1961-04-24 | Basil | Tramer | F | 1992-05-04 | | 10050 | 1958-05-21 | Yinghua | Dredge | M | 1990-12-25 | | 10056 | 1961-09-01 | Brendon | Bernini | F | 1990-02-01 | | 10058 | 1954-10-01 | Berhard | McFarlin | M | 1987-04-13 | | 10060 | 1961-10-15 | Breannda | Billingsley | M | 1987-11-02 | +--------+------------+------------+-------------+--------+------------+ 10 rows in set (0.00 sec)
MySQLでは、正規表現で大文字小文字を識別しない点に注意しましょう。
さらに複雑な条件のサンプル。
# select * from employees where first_name like in ( 'Be%', 'Ba%', 'An%', '%A' ) limit 10;
カッコと|(パイプ)を使った正規表現を入れ子にすることで実現できます。
mysql> select * from employees where first_name regexp '(^(Be|Ba|An).*|.*A$)' limit 10; +--------+------------+------------+-------------+--------+------------+ | emp_no | birth_date | first_name | last_name | gender | hire_date | +--------+------------+------------+-------------+--------+------------+ | 10002 | 1964-06-02 | Bezalel | Simmel | F | 1985-11-21 | | 10006 | 1953-04-20 | Anneke | Preusig | F | 1989-06-02 | | 10008 | 1958-02-19 | Saniya | Kalloufi | M | 1994-09-15 | | 10014 | 1956-02-12 | Berni | Genin | M | 1987-03-11 | | 10034 | 1962-12-29 | Bader | Swan | M | 1988-09-21 | | 10049 | 1961-04-24 | Basil | Tramer | F | 1992-05-04 | | 10050 | 1958-05-21 | Yinghua | Dredge | M | 1990-12-25 | | 10058 | 1954-10-01 | Berhard | McFarlin | M | 1987-04-13 | | 10060 | 1961-10-15 | Breannda | Billingsley | M | 1987-11-02 | | 10062 | 1961-11-02 | Anoosh | Peyn | M | 1991-08-30 | +--------+------------+------------+-------------+--------+------------+ 10 rows in set (0.00 sec)
また、パターンマッチ条件自体を動的に変えたい場合は、正規表現とconcat、group_concatでパターンマッチ文字列を自動生成する方法もあります。
【関連記事】
▶【SQL】LIKE+INに変わる方法とは?同じ動作が期待できる方法の構築について解説。
まとめ
- SQLでlike+inはSyntax errorになる
- orでlike条件を列挙することで代替可能だが、コードが冗長になる欠点あり
- 一部のDBMSでは、正規表現で代替できる。