MySQLの文字列結合の使い方について、サンプルSQLを紹介しながらまとめています。
以下、データベースとして、MySQLのサンプルデータベースEmployeesを使っています。
サンプルデータベースのインストール方法は、下記を参考にしてください。
【関連記事】
▶MySQLの入門には、GUIツールで慣れ、サンプルDBを使った学習が効果的
MySQLで文字列を連結するには、CONCATを使う
文字列を連結するには、次のようにします。
mysql> select CONCAT("By", "The", "Way"); +----------------------------+ | CONCAT("By", "The", "Way") | +----------------------------+ | ByTheWay | +----------------------------+
MySQL :: MySQL 5.6 リファレンスマニュアル :: 12.5 文字列関数 CONCAT
テーブルのカラムを結合するには、CONCATにカラム名を指定
CONCATの引数にカラム名を指定することで、テーブルのカラムを結合できます。
mysql> select CONCAT( dept_no, ":", dept_name) from departments; +----------------------------------+ | CONCAT( dept_no, ":", dept_name) | +----------------------------------+ | d009:Customer Service | | d005:Development | | d002:Finance | | d003:Human Resources | | d001:Marketing | | d004:Production | | d006:Quality Management | | d008:Research | | d007:Sales | +----------------------------------+
上記SQLは、departments(部署)テーブルのdept_no(部署番号)と”:”(コロン)とdept_name(部署名)を結合します。
複数の文字列を入れ子で連結可能
CONCATの引数に、CONCATを指定する入れ子構造も可能です。
mysql> select CONCAT("This MySQL version is ",CONCAT("5.","7.","28")); +---------------------------------------------------------+ | CONCAT("This MySQL version is ",CONCAT("5.","7.","28")) | +---------------------------------------------------------+ | This MySQL version is 5.7.28 | +---------------------------------------------------------+
その他、CONCATの基本的な使い方は以下の記事を参考になさってください。
【関連記事】
▶MySQLのCONCATとは?概要と基礎〜応用の使い方を解説!
CONCATの使い方応用編
結合文字列にNULLが含まれると、結果がNULLになるのを回避するにはIFNULL
CONCATの引数のどこかに一つでもNULLが入っていると、結合結果がNULLになります。
select CONCAT("This","Is",NULL); +--------------------------+ | CONCAT("This","Is",NULL) | +--------------------------+ | NULL | +--------------------------+
IFNULLを組み合わせて、NULLの箇所を別の文字列や空文字に変換可能です。IFNULL()は、第一引数がNULLだった場合に第二引数を返す関数です。
mysql> select CONCAT("This","Is",IFNULL(NULL,"")); +-------------------------------------+ | CONCAT("This","Is",IFNULL(NULL,"")) | +-------------------------------------+ | ThisIs | +-------------------------------------+
結合文字列に改行を入れるには、改行コードをCONCATする
CONCATには、制御コード(改行コード)を指定することも可能です。
mysql> select CONCAT("MySQL","\n", "5.7.28"); +--------------------------------+ | CONCAT("MySQL","\n", "5.7.28") | +--------------------------------+ | MySQL 5.7.28 | +--------------------------------+
上記SQLでは、”\n”(Linuxの改行コード)を結合して、「MySQL」+改行+「5.7.28」にしています。
GROUP_CONCATでGROUP BY集計を各1行に集約
GROUP_CONCATで、複数レコードを1つの文字列に結合できます。
mysql> select GROUP_CONCAT(dept_name SEPARATOR ",") from departments; +-------------------------------------------------------------------------------------------------------------+ | GROUP_CONCAT(dept_name SEPARATOR ",") | +-------------------------------------------------------------------------------------------------------------+ | Customer Service,Development,Finance,Human Resources,Marketing,Production,Quality Management,Research,Sales | +-------------------------------------------------------------------------------------------------------------+
上記のSQLは、departmens(部署)テーブルのdept_name(部署名)を”,”(カンマ)で連結して一つの文字列にします。
参考)MySQL :: MySQL 5.6 リファレンスマニュアル :: 12.19.1 GROUP CONCAT関数
GROUP BYと組み合わせて、複数行のデータを1行にまとめて簡潔に表示することが可能です。
SELECT departments.dept_name, GROUP_CONCAT(DISTINCT titles.title SEPARATOR ',') FROM employees LEFT JOIN dept_emp ON employees.emp_no = dept_emp.emp_no LEFT JOIN departments ON dept_emp.dept_no = departments.dept_no LEFT JOIN titles ON employees.emp_no = titles.emp_no GROUP BY departments.dept_name;
上記のSQLは、部署名(departments.dept_name)ごとに所属する職種(titles.title)をカンマで連結して部署ごとに1行づつ表示します。実行するとこうなります。
+--------------------+-----------------------------------------------------------------------------------------+ | dept_name | GROUP_CONCAT(distinct titles.title SEPARATOR ',') | +--------------------+-----------------------------------------------------------------------------------------+ | Customer Service | Assistant Engineer,Engineer,Manager,Senior Engineer,Senior Staff,Staff,Technique Leader | | Development | Assistant Engineer,Engineer,Manager,Senior Engineer,Senior Staff,Staff,Technique Leader | | Finance | Manager,Senior Staff,Staff | | Human Resources | Manager,Senior Staff,Staff | | Marketing | Manager,Senior Staff,Staff | | Production | Assistant Engineer,Engineer,Manager,Senior Engineer,Senior Staff,Staff,Technique Leader | | Quality Management | Assistant Engineer,Engineer,Manager,Senior Engineer,Technique Leader | | Research | Assistant Engineer,Engineer,Manager,Senior Engineer,Senior Staff,Staff,Technique Leader | | Sales | Manager,Senior Staff,Staff | +--------------------+-----------------------------------------------------------------------------------------+
where条件にCONCATを使うと遅い
SQLのwhere節にCONCATを指定することも可能です。
mysql> select * from employees where concat(first_name," ",last_name) = "Jayson Mandell"; +--------+------------+------------+-----------+--------+------------+ | emp_no | birth_date | first_name | last_name | gender | hire_date | +--------+------------+------------+-----------+--------+------------+ | 10096 | 1954-09-16 | Jayson | Mandell | M | 1990-01-14 | +--------+------------+------------+-----------+--------+------------+
ただし、concatで条件指定した場合、インデックスが使用できないため、対象データが多くなるほどレスポンスが悪くなります。
【関連記事】
▶MySQLのインデックス作成方法 効いてないと思ったらexplainで確認する
employeesテーブルのfist_nameとlast_nameにインデックスを設定して、試してみます。
mysql> alter table employees add index index3(first_name,last_name);
上記SQLは、employeesのfirst_nameとlast_nameの組み合わせにindex3という名前でインデックスを設定します。
mysql> explain select * from employees where concat(first_name," ",last_name) = "Jayson Mandell"; +----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------------+ | 1 | SIMPLE | employees | NULL | ALL | NULL | NULL | NULL | NULL | 299025 | 100.00 | Using where | +----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
concatをwhereに使ったSQLをexplainして、実行計画をチェックしてみると「type=ALL」のテーブルフルスキャンが実行されています。
concatを使わないwhere条件に書き換えると、以下のようになりました。
mysql> explain select * from employees where first_name = "Jayson" and last_name="Mandell"; +----+-------------+-----------+------------+------+---------------+--------+---------+-------------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+---------------+--------+---------+-------------+------+----------+-------+ | 1 | SIMPLE | employees | NULL | ref | index3 | index3 | 34 | const,const | 1 | 100.00 | NULL | +----+-------------+-----------+------------+------+---------------+--------+---------+-------------+------+----------+-------+
設定したインデックスindex3が利用されていることが確認できます。
データの多いテーブルに対しては、where条件にconcatを使うのを避けるのが良いでしょう。
まとめ
- MySQLで文字列を連結するには、CONCATを使う
- 複数レコードを連結するには、GROUP_CONCATを使う。GROUP BYと組み合わせて、1行に複数データを集約可能。
- NULLを含む文字列を連結するには、IFNULLを組み合わせてNULLを別の文字列に変換する
- WHERE節で、件数の多いテーブルにCONCATを使うと、インデックスが利用できないためパフォーマンスが低下する