1対Nのテーブル2つがある場合、N側のテーブルはデータを縦持ちするはず。
しかしながら、1側のテーブルに合わせて、1行で表示したい場合の小ネタ。
せっかくなので、MariaDB10.7の新機能も添えて紹介。
たとえば、こんなテーブルとデータがあります。
CREATE TABLE `question` ( `question_id` int(11) NOT NULL COMMENT '問題ID', `question_text` text NOT NULL COMMENT '本文', PRIMARY KEY (`question_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='問題' > select * from question; +-------------+--------------------------------------------------------------------------------------------------------------+ | question_id | question_text | +-------------+--------------------------------------------------------------------------------------------------------------+ | 1 | しゃっくりはある調味料をなめると止まります。ある調味料とはなんでしょう? | +-------------+--------------------------------------------------------------------------------------------------------------+ |
CREATE TABLE `question_select` ( `question_id` int(11) NOT NULL COMMENT '問題ID', `select_id` int(11) NOT NULL COMMENT '選択肢ID', `select_text` text NOT NULL COMMENT '選択肢内容', PRIMARY KEY (`question_id`,`select_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='選択肢' > select * from question_select; +-------------+-----------+-------------+ | question_id | select_id | select_text | +-------------+-----------+-------------+ | 1 | 1 | お酢 | | 1 | 2 | 砂糖 | | 1 | 3 | 醤油 | | 1 | 4 | 塩 | +-------------+-----------+-------------+ |
これを1行で表示したい場合、以下のようにやる。
> with t as ( select t1.question_id, t1.question_text, sformat('[{}]', group_concat(distinct json_object('select_id', t2.select_id, 'select_text', t2.select_text) order by t2.select_id)) as select_list from question as t1 join question_select as t2 on t1.question_id = t2.question_id group by t1.question_id, t1.question_text ) select question_id, question_text, json_value(select_list, '$[0].select_id') as select_id_1, json_value(select_list, '$[0].select_text') as select_text_1, json_value(select_list, '$[1].select_id') as select_id_2, json_value(select_list, '$[1].select_text') as select_text_2, json_value(select_list, '$[2].select_id') as select_id_3, json_value(select_list, '$[2].select_text') as select_text_3, json_value(select_list, '$[3].select_id') as select_id_4, json_value(select_list, '$[3].select_text') as select_text_4 from t ; |
+-------------+--------------------------------------------------------------------------------------------------------------+-------------+---------------+-------------+---------------+-------------+---------------+-------------+---------------+ | question_id | question_text | select_id_1 | select_text_1 | select_id_2 | select_text_2 | select_id_3 | select_text_3 | select_id_4 | select_text_4 | +-------------+--------------------------------------------------------------------------------------------------------------+-------------+---------------+-------------+---------------+-------------+---------------+-------------+---------------+ | 1 | しゃっくりはある調味料をなめると止まります。ある調味料とはなんでしょう? | 1 | お酢 | 2 | 砂糖 | 3 | 醤油 | 4 | 塩 | +-------------+--------------------------------------------------------------------------------------------------------------+-------------+---------------+-------------+---------------+-------------+---------------+-------------+---------------+ |
ポイントはgroup_concatで横持ちに変換する際に、JSON配列にしてしまうこと。
集計するときに結構使える技。
今回はMariaDBの10.7新機能であるsformat関数を使ってみましたが、concat関数でも代用可能です。
MySQLの場合は、「->>」とかで、JSONから値を取り出す感じですかね。
以上