MySQLのJSON_TABLE関数が便利だった件
はじめに
最近 MySQL で JSON_TABLE を使う機会がありました。
JSON をそのまま SQL の中で扱えるのって意外と便利で、「もっと早く知っておきたかった!」と思ったので、簡単に紹介してみます。
従来のやり方とちょっとした不便さ
MySQL には JSON_EXTRACT や ->> 演算子など、JSON を操作する方法はいくつかあります。ただ、JSON配列を扱おうとすると、どうしても複雑になってしまいがちです。
たとえば「外部APIから取得した複数のユーザーデータ(JSON配列)を、データベースの情報と組み合わせて処理する」ケース。
従来の書き方(単純化した例)
-- 外部APIから複数のユーザー情報を取得した場合
-- 実際には配列の要素数が事前に分からないため、
-- アプリケーション側で個別にクエリを実行することが多い
-- ユーザーID: 101, スコア: 85, カテゴリ: premium
SELECT u.id AS user_id, u.name AS user_name, 85 as score, 'premium' as category
FROM users u WHERE u.id = 101;
-- ユーザーID: 202, スコア: 92, カテゴリ: standard
SELECT u.id AS user_id, u.name AS user_name, 92 as score, 'standard' as category
FROM users u WHERE u.id = 202;
-- ユーザーID: 303, スコア: 78, カテゴリ: premium
SELECT u.id AS user_id, u.name AS user_name, 78 as score, 'premium' as category
FROM users u WHERE u.id = 303;
-- このように、データの数だけクエリを実行する必要がある
-- (実際にはアプリケーション側でループ処理により動的に生成)
👉 実際には IN句 を使ってまとめて取得することも可能ですが、
JSON配列をそのままSQLに渡して処理できるのが JSON_TABLE の強みです。
JSON_TABLEとは?
JSON_TABLE は MySQL 8.0 以降で使える関数で、JSON配列をテーブルのように展開できる のが特徴です。
基本構文
JSON_TABLE(json_doc, path COLUMNS (
column_name column_type PATH 'json_path'
))
-
json_doc: JSON文字列(カラムや変数でもOK) -
path: 配列のどの部分を展開するか("$[*]"で配列全体) -
COLUMNS: JSONから取り出して列として定義する内容
イメージとしては、JSON配列を「仮想テーブル」に変換して、
そのまま JOIN できるようになる感じです。
サンプルで見てみる
JSON_TABLEを使った例
-- テスト用:外部APIから取得したユーザーデータ(JSON配列)
SET @api_data = '[
{"user_id": 101, "score": 85, "category": "premium"},
{"user_id": 202, "score": 92, "category": "standard"},
{"user_id": 303, "score": 78, "category": "premium"}
]';
-- JSON_TABLEを使って配列を展開し、ユーザー情報と組み合わせ
SELECT
u.id AS user_id,
u.name AS user_name,
jt.score,
jt.category
FROM JSON_TABLE(
@api_data, "$[*]" COLUMNS (
user_id BIGINT PATH "$.user_id",
score INT PATH "$.score",
category VARCHAR(20) PATH "$.category"
)
) AS jt
INNER JOIN users u ON u.id = jt.user_id
ORDER BY jt.score DESC;
このSQLでは、@api_data のJSON配列を JSON_TABLE で展開して、その結果を users とJOINしています。
👉 従来の方法と比べて、1回のクエリで全て処理できるので、パフォーマンスが向上し、コードもシンプルになります。
実用例:ネストした注文データの処理
もう一つ、ネストした配列を扱う実用例を紹介します。
注文データに含まれる商品リストを展開する場合です。
-- 単一注文の商品データ(ネストした構造)
SET @order_data = '{
"order_id": 1001,
"user_id": 101,
"items": [
{"name": "マウス", "price": 1500},
{"name": "キーボード", "price": 3200},
{"name": "マウスパッド", "price": 800}
]
}';
-- ネストした商品配列を展開
SELECT
JSON_EXTRACT(@order_data, '$.order_id') as order_id,
jt.product_name,
jt.price
FROM JSON_TABLE(
@order_data, "$.items[*]" COLUMNS (
product_name VARCHAR(100) PATH "$.name",
price INT PATH "$.price"
)
) AS jt;
実行結果イメージ:
| order_id | product_name | price |
|---|---|---|
| 1001 | マウス | 1500 |
| 1001 | キーボード | 3200 |
| 1001 | マウスパッド | 800 |
👉 このように、注文データの中にある商品配列を展開して、注文明細として表示できます。JSONの構造が少し複雑でも、"$.items[*]"でネストした配列を指定するだけで簡単に処理できます。
便利だと思ったポイント
実際に使ってみて便利だと感じた点はこんなところです:
- JSON配列をそのままSQLに渡せる
- 配列の要素数に関係なく、同じSQLで処理できる
- 複数のクエリを発行せずに済むので効率的
- フロントエンドから送信されたJSONデータを直接SQLで処理できる
注意点
- MySQL 8.0 以降でしか使えません
- JSONの形式が想定と違うとエラーになる場合があります(
ERROR ON ERRORで制御可能) - 大量データに使うとパフォーマンスに影響することもあるので、インデックスの設計に注意
- JSON_TABLEで展開したデータは一時的なものなので、永続化が必要な場合は別途処理が必要
まとめ
JSON_TABLE を使うと、JSON配列をそのままSQLで展開してJOINできるので、フロントエンドとの連携や一括処理がとても楽になります。
特に管理画面での一括操作やAPI連携など、JSON データを頻繁に扱う場面では、従来の方法と比べて大幅に開発効率が向上します。
MySQL 8.0 を使っているならぜひ試してみてください!
Discussion