🙄

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