はじめに
MySQL 9.4 から、JSON Duality View という機能が実装されています。
MySQL now supports JSON duality views, which provide a way to expose data stored in relational tables as JSON documents. Such views can be created, altered, dropped, and viewed using CREATE JSON DUALITY VIEW and ALTER JSON DUALITY VIEW (both implemented in this release); DROP VIEW and SHOW CREATE VIEW now work with JSON duality views as well as SQL views.
これは、呼び出したときに JSON 形式で値を生成するビューとして扱うことが可能な、仮想 JSON ドキュメントです。
構造化データ(リレーショナルデータ)と半構造化データ(JSON データ)の両方を統合して、アプリケーションからどちらのデータモデルでも扱うことができるようになります。
正規化されたテーブルがアプリからは JSON ドキュメントのように扱えるようになるため、RDB の整合性を保ちつつ、API では JSON ドキュメントとして読み書きが可能です。
今回はこの機能の詳細や使用方法などについて確認していきたいと思います。
概要
従来、MySQL Server 5.7 から JSON データ型が実装されており、半構造化データを取り扱うこと自体は可能でした。
JSON データ型を利用することで、データを ORM マッピングすることなく扱うことができるようになるため、アプリケーションからの汎用性や利便性を高めることができました。
しかし、こうした JSON ドキュメント・ストアとしての運用は、データ量が多くなるにつれて、格納された JSON データの正規性を維持することが難しくなっていき、データの重複が発生する恐れがあるなど、管理が煩雑になる側面がありました。
JSON Duality View は、データの参照整合性やデータ正規化などを構造化データとして保持しながら、アプリケーションが使いやすい半構造化データとして直接シームレスに参照や更新処理をおこなうことができます。
これによって、リレーショナルデータベースの強みを損なうことなく、JSON ドキュメント中心のアプリケーションでも容易に扱うことができるようになります。
検証環境
今回の検証は、以下の環境でおこないました。
- Rocky Linux release 9.6 (Blue Onyx)
- MySQL Community Server 9.7.0
事前に、以下のテーブルを作成しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
mysql> CREATE DATABASE sales; mysql> CREATE TABLE sales.customers ( customer_id INT PRIMARY KEY, name VARCHAR(100) ); mysql> CREATE TABLE sales.orders ( order_id INT PRIMARY KEY, customer_id INT, product VARCHAR(100), amount DECIMAL(10,2), FOREIGN KEY (customer_id) REFERENCES customers(customer_id) ); mysql> INSERT INTO sales.customers VALUES (1, "Alice"), (2, "Bob"); mysql> INSERT INTO sales.orders VALUES (1, 1, "Milk", 10), (2, 1, "Curd", 5), (3, 2, "Flour", 20), (4, 2, "Biscuits", 5); |
作成方法
JSON Duality View は以下のように CREATE JSON DUALITY VIEW コマンドで作成をおこないます。
なお RELATIONAL についてはオプションであり書いても効果はないため、省略しても問題ありません。
本記事では、customers テーブルをルートテーブル(JSON ドキュメント全体の基点となるテーブル)としたビューと、orders テーブルをルートテーブルとしたビューの 2 つを用意します。これは後半の更新時の検証において、どちらをルートテーブルにするかでデータの追加しやすさが変わるためです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
mysql> CREATE JSON RELATIONAL DUALITY VIEW sales.customer_orders_dv AS SELECT JSON_DUALITY_OBJECT( WITH(INSERT,UPDATE,DELETE) '_id': customers.customer_id, 'customer_name': customers.name, 'orders': ( SELECT JSON_ARRAYAGG( JSON_DUALITY_OBJECT( WITH(INSERT,UPDATE,DELETE) 'order_id': orders.order_id, 'product': orders.product, 'amount': orders.amount ) ) FROM sales.orders WHERE orders.customer_id = customers.customer_id ) ) FROM sales.customers; mysql> CREATE JSON RELATIONAL DUALITY VIEW sales.order_dv AS SELECT JSON_DUALITY_OBJECT( WITH(INSERT,UPDATE,DELETE) '_id' : order_id, 'product' : orders.product, 'amount' : orders.amount, 'customer': ( SELECT JSON_DUALITY_OBJECT( WITH(INSERT,UPDATE) 'customer_id': customers.customer_id, 'customer_name': customers.name ) FROM sales.customers WHERE customers.customer_id = orders.customer_id ) ) FROM sales.orders; |
上記の SQL の詳細については以下の通りです。
- JSON Duality View は、通常のビュー(SQL View) と同じ名前空間を使用しています
- 他のビューと同じ名前で作成することはできません
CREATE OR REPLACEを使用して、通常のビューと JSON Duality View を置き換えることはできません
- スキーマ名を指定しない場合は現在のスキーマに作成されます
- 内容はルートオブジェクトとして、
SELECT JSON_DUALITY_OBJECT() FROM <テーブル名>と記載する必要がありますJSON_DUALITY_OBJECT()を 1 つだけコールします- FROM 句は単一のテーブルを参照する必要があります(ルートテーブル、親テーブル)
- 集合演算(
UNION、INTERSECT、EXCEPT) および共通テーブル式(WITH) はサポートされていません。 WHERE、JOIN、GROUP BY、ORDER BY、HAVING、WINDOW、LIMIT句はサポートされていません
DEFINER 属性については通常のビューと同様の挙動をおこなうため、説明を割愛しています。
なお、作成時の文法や要件については長くなってしまうため、文末の「【参考】 JSON Duality View 作成時の要件や注意事項について」にまとめているのでご参照ください。
参照と更新
それでは実際に JSON Duality View への参照および更新系の処理をおこなっていきます。
なお、JSON Duality View では _metadata オブジェクト内に etag フィールドが暗黙的に作成されており、データ変更情報の追跡に使用されます。
参照(SELECT)
JSON Duality View は通常のビューと同様に SELECT 文でデータを参照することが可能です。
実態としては data という名称の列で構成されているため、たとえば _id キーでフィルタリングをおこなう場合は以下のように記載します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
mysql> SELECT JSON_PRETTY(data) FROM sales.customer_orders_dv WHERE data->'$._id' = 1\G *************************** 1. row *************************** JSON_PRETTY(data): { "_id": 1, "orders": [ { "amount": 10.00, "product": "Milk", "order_id": 1 }, { "amount": 5.00, "product": "Curd", "order_id": 2 } ], "_metadata": { "etag": "a6f0e76602398bc2df6fdd09494ae07b" }, "customer_name": "Alice" } |
JSON ドキュメントであるため、実際にデータを取り出すときには、以下のように JSON 関数も利用可能です。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
### Milk を購入したユーザー(と購入商品一覧)を表示する mysql> SELECT data->>'$.customer_name' AS customer_name, JSON_EXTRACT(data, '$.orders[*].product') AS products FROM sales.customer_orders_dv WHERE JSON_CONTAINS(data, '{"product":"Milk"}', '$.orders'); +---------------+------------------+ | customer_name | products | +---------------+------------------+ | Alice | ["Milk", "Curd"] | +---------------+------------------+ 1 row in set (0.000 sec) |
更新(DML)
JSON Duality View に対して更新処理をおこなうことで、入力された JSON ドキュメントの構文チェックを自動で検証しながら、複数のテーブルに対する DML が分解して実行されます。
これによって、データの一貫性を保ったまま JSON ドキュメント内でシームレスに DML を実行することができます。
実行する際にはいくつか注意事項があるので、個別に説明していきます。なお、これ以外の詳細な挙動については、以下の公式リファレンスをご確認ください。
27.7.2 DML Operations on JSON Duality Views
変更タグの指定
JSON Duality View を作成する際には JSON_DUALITY_OBJECT() に変更タグをつけて DML の実行を制御することが可能です。
|
1 2 3 |
SELECT JSON_DUALITY_OBJECT( WITH(INSERT,UPDATE,DELETE) '_id': customer_id, (...) |
指定していない操作についてはエラーとなります。これによって、偶発的なデータ変更を防止して、明示的かつ監視可能な状態で操作することが可能になります。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
mysql> CREATE JSON RELATIONAL DUALITY VIEW sales.order_test AS SELECT JSON_DUALITY_OBJECT( '_id' : order_id, 'product' : product, 'amount' : amount ) FROM sales.orders; Query OK, 0 rows affected (0.004 sec) mysql> INSERT INTO order_test VALUES('{ "_id" : 1, "product" : "Free Paper", "amount" : 0.00 }'); ERROR 6490 (HY000): Missing INSERT tag on table `sales`.`orders`, path '$'. |
INSERT 実行時はルートオブジェクトに対しての追加が必要
INSERT 文を実行する際は、以下のように JSON ドキュメントを入力することで、各テーブルにデータを挿入することができます。
以下の例では、customers テーブルに 1 行、orders テーブルに 2 行のデータが挿入されます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
### 検証用に一度テーブルデータを削除 mysql> DELETE FROM sales.orders; DELETE FROM sales.customers; Query OK, 0 rows affected (0.000 sec) ### データを挿入 mysql> INSERT INTO sales.customer_orders_dv VALUES ( '{ "customer_name": "Alice", "_id": 1, "orders": [ {"order_id": 1, "product": "Laptop", "amount": 1299.99}, {"order_id": 2, "product": "Mouse", "amount": 19.99} ] }'); Query OK, 3 rows affected (0.003 sec) Rows affected: 3 Warnings: 0. ### 実際のテーブルデータを確認 mysql> SELECT * FROM sales.customers; SELECT * FROM sales.orders; +-------------+-------+ | customer_id | name | +-------------+-------+ | 1 | Alice | +-------------+-------+ 1 row in set (0.000 sec) +----------+-------------+---------+---------+ | order_id | customer_id | product | amount | +----------+-------------+---------+---------+ | 1 | 1 | Laptop | 1299.99 | | 2 | 1 | Mouse | 19.99 | +----------+-------------+---------+---------+ 2 rows in set (0.000 sec) |
ただし、挿入はルートテーブルへの _id をキーとして実行されているため、以下のように同一のキーで挿入すると重複キーエラーとなります。そのような場合は、追加したいテーブルをルートオブジェクトとした JSON Duality View を別途用意する必要があります。
なお、サブオブジェクトに値を挿入しなくてもデータを追加することが可能です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
### 以下のクエリは既存の _id を指定しているので重複キーエラーとなる mysql> INSERT INTO sales.customer_orders_dv VALUES ( '{ "customer_name": "Alice", "_id": 1, "orders": [ {"order_id": 3, "product": "Monitor", "amount": 299.99}, {"order_id": 4, "product": "Desk", "amount": 559.99} ] }'); ERROR 1062 (23000): Duplicate entry '1' for key 'customers.PRIMARY' ### order テーブルをルートテーブルとした JSON Duality View であれば挿入可能 mysql> INSERT INTO sales.order_dv VALUES('{ "_id" : 3, "product" : "Desk", "amount" : 499.99, "customer" : { "customer_id" : 1, "customer_name" : "Alice" } }'); Query OK, 1 row affected (0.004 sec) Rows affected: 1 Warnings: 0. ### 以下のようにルートオブジェクトにのみデータを追加することは可能 mysql> INSERT INTO sales.customer_orders_dv VALUES ( '{ "customer_name": "Alice_junior", "_id": 2 }'); Query OK, 1 row affected (0.003 sec) Rows affected: 1 Warnings: 0. ### 実際のテーブルデータを確認(ルートオブジェクトとして更新した各テーブルに 1 行ずつ挿入されている) mysql> SELECT * FROM sales.customers; SELECT * FROM sales.orders; +-------------+--------------+ | customer_id | name | +-------------+--------------+ | 1 | Alice | | 2 | Alice_junior | +-------------+--------------+ 2 rows in set (0.001 sec) +----------+-------------+---------+---------+ | order_id | customer_id | product | amount | +----------+-------------+---------+---------+ | 1 | 1 | Laptop | 1299.99 | | 2 | 1 | Mouse | 19.99 | | 3 | 1 | Desk | 499.99 | +----------+-------------+---------+---------+ 3 rows in set (0.000 sec) |
そのままだと UPDATE 実行時に JSON ドキュメントが置換
UPDATE 文はルートオブジェクトとサブオブジェクトのどちらも更新対象とすることが可能です。
ただし、JSON Duality View は単一列である data と行識別子である _id でのみ構成されているため、左辺は SET data = のように指定する必要があります。
したがって、そのままでは更新したサブオブジェクトの内容が完全に入れ替えられるため、記載した内容によっては行数が少なくなる可能性もあります。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
### _id = 1 に対して orders サブオブジェクトのデータを更新する mysql> UPDATE sales.customer_orders_dv SET data = ' { "_id" : 1, "customer_name" : "Alice", "orders" : [ { "order_id" : 1, "product" : "Laptop", "amount" : 999.99 }, { "order_id" : 4, "product" : "Keyboard", "amount" : 29.99 } ] }' WHERE JSON_EXTRACT(data, '$._id') = 1; Query OK, 4 rows affected, 1 warning (0.004 sec) Rows affected: 4 Warnings: 1. ### 実際のテーブルデータからは order_id の 2 と 3 が消えて、すべて先ほどの内容に置換される mysql> SELECT * FROM sales.customers; SELECT * FROM sales.orders; +-------------+--------------+ | customer_id | name | +-------------+--------------+ | 1 | Alice | | 2 | Alice_junior | +-------------+--------------+ 2 rows in set (0.000 sec) +----------+-------------+----------+--------+ | order_id | customer_id | product | amount | +----------+-------------+----------+--------+ | 1 | 1 | Laptop | 999.99 | | 4 | 1 | Keyboard | 29.99 | +----------+-------------+----------+--------+ 2 rows in set (0.000 sec) |
もし既存の内容に対して追記をおこないたい場合は、JSON_ARRAY_APPEND() 関数などを使用することで、疑似的に対応することが可能です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
### JSON_ARRAY_APPEND() を使用して追記 mysql> UPDATE sales.customer_orders_dv SET data = JSON_ARRAY_APPEND( data, '$.orders', JSON_OBJECT( 'order_id', 5, 'product', 'Monitor', 'amount', 199.99 ) ) WHERE JSON_VALUE(data, '$._id') = 1; Query OK, 1 row affected (0.004 sec) Rows affected: 1 Warnings: 0. ### 既存のデータを残したまま 5 を追記することが可能 mysql> SELECT * FROM sales.orders; +----------+-------------+----------+--------+ | order_id | customer_id | product | amount | +----------+-------------+----------+--------+ | 1 | 1 | Laptop | 999.99 | | 4 | 1 | Keyboard | 29.99 | | 5 | 1 | Monitor | 199.99 | +----------+-------------+----------+--------+ 3 rows in set (0.000 sec) |
楽観的並行性制御(LOCC) によるデータ整合性の維持
JSON Duality View ではデータの整合性を保つために、ETAG() を利用した楽観的並行性制御(LOCC) を採用しています。
SELECT 文を実行した際には、_metadata.etag フィールドに現在の値を ETAG() でハッシュ計算した一意の値が格納されていることがわかります。
|
1 2 3 4 5 6 7 8 9 |
mysql> SELECT JSON_PRETTY(data) FROM customer_orders_dv WHERE data->'$._id' = 1\G *************************** 1. row *************************** JSON_PRETTY(data): { "_id": 1, (...) "_metadata": { "etag": "75df9c360eb4b47e2438f9598bd7886b" }, (...) |
データが更新された場合はこの _metadata.etag の値も更新されます。もし DML を実行する前後で値が変更されていることを検知した場合、そのクエリはエラーとなってロールバックされます。
そのため、値を更新する前に _metadata.etag の値を確認しておき、データ更新時に確認することで、データの整合性を保つことが可能です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
### トランザクション 1 mysql> BEGIN; mysql> UPDATE sales.customer_orders_dv SET data = ' { "_id" : 1, "customer_name" : "Alice", "orders" : [ { "order_id" : 1, "product" : "Laptop", "amount" : 899.99 } ] }' WHERE JSON_EXTRACT(data, '$._id') = 1; Query OK, 1 row affected, 1 warning (0.002 sec) Rows affected: 1 Warnings: 1. mysql> COMMIT; # このコマンドはトランザクション 2 でトランザクションを開始してから実行する ### トランザクション 2 mysql> BEGIN; mysql> SELECT data->>'$._metadata.etag' INTO @etag FROM sales.customer_orders_dv WHERE data->>'$._id' = '1'; mysql> mysql> UPDATE sales.customer_orders_dv SET data = JSON_SET( CAST('{ "_id": 1, "customer_name": "Alice", "orders": [ { "order_id": 1, "product": "Laptop", "amount": 699.99 } ] }' AS JSON), '$._metadata', JSON_OBJECT('etag', @etag) ) WHERE data->>'$._id' = '1'; ERROR 6494 (HY000): Cannot update JSON duality view. The ETAG of the document in the database did not match the ETAG '"eac0fee85aac63fdefd527273ce00d02"' passed in. |
まとめ
ここまで、JSON Duality View の作成方法や基本的な使用方法について確認してきました。
JSON Duality View を利用することで、MySQL によるデータの一貫性や運用のしやすさを維持しながら、JSON ドキュメントによるシームレスなアプリケーションの利用が可能となります。
MySQL Server 9.7 からは Community Edition でも DML を実行できるようになったため、実用に足る機能になったのではないかと思います。
これを機に、JSON ドキュメント・ストアとしての MySQL Server を検討してみてはいかがでしょうか?
【参考】 JSON Duality View 作成時の要件や注意事項について
ここでは、JSON Duality View を作成する際の記載方法について改めて説明しています。
まずはルートオブジェクトとして、 SELECT JSON_DUALITY_OBJECT() FROM <テーブル名> と記載する必要があります。
記事の中でも記載していますが、その際の要件は以下の通りです。
- JSON_DUALITY_OBJECT() を 1 つだけコールします
- FROM 句は単一のテーブルを参照する必要があります(ルートテーブル、親テーブル)
- 集合演算(
UNION、INTERSECT、EXCEPT) および共通テーブル式(WITH) はサポートされていません。 WHERE、JOIN、GROUP BY、ORDER BY、HAVING、WINDOW、LIMIT句はサポートされていません
JSON_DUALITY_OBJECT() 関数の詳細について
JSON_DUALITY_OBJECT() は、以下の種類の引数を取ることができます。
- JSON オブジェクト形式のキーと値のペア : 例 …
'_id': customer_id - オプションのテーブル注釈式(変更タグ) : 例 …
WITH(INSERT,UPDATE,DELETE)
各引数の詳細について、それぞれ説明していきます。
JSON オブジェクト形式のキーと値のペア
JSON オブジェクト形式のキーと値のペアについては複数記載することが可能で、その場合はカンマ区切りで記載をおこないます。
記載ルールおよび要件については以下の通りです。
- ルートオブジェクトには、ルートテーブルの主キーを表す
_idという名前のキーを含める必要があります - ルートテーブルおよび各オブジェクトで参照されるテーブルを含むすべてのテーブルは、主キーを持っている必要があります
- JSON オブジェクトとして投影(射影、出力)する列には、参加するすべてのテーブルの主キーを含める必要があります
- 2026/04/20 時点で、複合主キーには対応していません
- ネストされたサブオブジェクトを使用可能ですが、以下の方法でルートテーブルと関連付ける必要があります
- 子テーブル(ネストされたオブジェクトで参照されるテーブル)の主キーと親テーブルの任意のカラム
- 親テーブルの主キーと子テーブルの任意のカラム
サブオブジェクトの記載方法について
サブオブジェクトの記載方法については、以下のサンプルを使ってさらに解説します。一部前述した要件と被っている内容もありますがご了承ください。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
【サンプル】 CREATE JSON RELATIONAL DUALITY VIEW orders_jdv AS ##### A SELECT JSON_DUALITY_OBJECT( '_id': orders.order_id, 'orderTime': orders.order_datetime, ##### B 'customerInfo': ( SELECT JSON_DUALITY_OBJECT( 'customerId': customers.customer_id, 'customer_name': customers.full_name, 'customerEmail': customers.email_address ) FROM customers WHERE customers.customer_id = orders.customer_id ), ##### C 'orderItems': ( SELECT JSON_ARRAYAGG( JSON_DUALITY_OBJECT( WITH (INSERT,UPDATE,DELETE) 'orderItemId': oi.line_item_id, 'quantity': oi.quantity ) ) FROM order_items oi WHERE orders.order_id = oi.order_id ) ) FROM orders; |
ルートオブジェクト (A)
A の部分はルートオブジェクトと呼ばれます。
以下のような構造になっており、サブオブジェクトをネストすることも可能です。
|
1 2 3 4 5 6 |
SELECT JSON_DUALITY_OBJECT( '_id' : <親テーブルの主キー> , ['<任意のキー名>' : <親テーブルの任意のカラム> ,] ['<任意のキー名>' : サブオブジェクト] ) FROM <親テーブル名> |
- ルートオブジェクトにはルート(親)テーブルの主キーを表す
_idという名前のキーを含める必要があります - 単一のテーブルを参照する必要があります
WHERE句は使用することができません
子テーブルの主キーと親テーブルの任意のカラムの関係性 (B)
子テーブルの主キーと親テーブルの任意のカラムを関連付けることで、親テーブルと子テーブルが 1 対 1 の関係性 (singleton_descendent_json_object) となります。
以下のような構造になっています。
|
1 2 3 4 5 6 7 8 9 |
'<任意のキー名>': ( SELECT JSON_DUALITY_OBJECT( '<任意のキー名>': <子テーブルの主キー>, ['<任意のキー名>': <子テーブルの任意のカラム>,] ['<任意のキー名>': <子テーブルの任意のカラム>] ) FROM <子テーブル名> WHERE <子テーブルの主キー> = <親テーブルの任意のカラム> ), |
- 値はルートオブジェクトのように、
JSON_DUALITY_OBJECT()を含むSELECT文によって定義されます - 子テーブルの主キーを値として含める必要があります
_idというキー名は使用することができません
- 単一のテーブルを参照する必要があります
- 親テーブルとの関係を定義する
WHERE句は必須で、以下のどちらかの記載をおこないますWHERE <子テーブルの主キー> = <親テーブルの外部キー>WHERE <子テーブルの主キー> = <親テーブルの任意のカラム>
親テーブルの主キーと子テーブルの任意のカラムの関係性 (C)
親テーブルの主キーと子テーブルの任意のカラムを関連付けることで、親テーブルと子テーブルが 1 対多の関係性 (nested_descendent_json_objects) となります。
以下のような構造になっています。
|
1 2 3 4 5 6 7 8 9 |
'<任意のキー名>': ( SELECT JSON_ARRAYAGG( JSON_DUALITY_OBJECT( '<任意のキー名>': <子テーブルの主キー>, ['<任意のキー名>': <子テーブルの任意のカラム>] ) ) FROM <子テーブル> WHERE <親テーブルの主キー> = <子テーブルの任意のカラム> |
- 値は
JSON_DUALITY_OBJECT()を含むJSON_ARRAYAGG()を使用したSELECT文によって定義されます _idというキー名である必要はありませんが、子テーブルの主キーを値として含める必要があります- 単一のテーブルを参照する必要があります
- 親テーブルとの関係を定義する
WHERE句は必須で、以下のどちらかの記載をおこないますWHERE <親テーブルの主キー> = <子テーブルの外部キー>WHERE <親テーブルの主キー> = <子テーブルの任意のカラム>
オプションのテーブル注釈式(変更タグ)
ルートオブジェクトあるいはサブオブジェクトに注釈(変更タグ)をつけて、テーブルへの書き込み機能を構成することができます。
以下のように、キーと値のペアの前に WITH 句で定義します。
|
1 2 3 |
SELECT JSON_DUALITY_OBJECT( WITH(INSERT,UPDATE,DELETE) '_id': customer_id, (...) |
該当オブジェクトのテーブルに対する注釈値を、カンマで区切ったリストで記載します。
INSERTあるいはNO INSERTUPDATEあるいはNO UPDATEDELETEあるいはNO DELETE
完全な書き込み機能を実現するためには、3 つの注釈値をすべて有効にする必要があります。
なお、MySQL Server 9.6 までは書き込み機能を有効化しても、実際に DML を実行するためには Enterprise Edition である必要がありました。
しかし、2026 年 4 月にリリースされた MySQL Server 9.7 からは Community Edition でも DML 操作をサポートするようになっています。
その他の挙動については以下の通りです。
- 順序は問いませんが、同じ注釈値を複数回指定することはできません
- 相反する値(たとえば
INSERTとNO INSERT)を含めることはできません - 注釈値を省略した場合、その相反する値を指定することと同義です
WITH()句を省略した場合、その JSON Duality View は読み取り専用になります
- サブオブジェクトにおいて
WHERE句に以下を指定しているとき、すなわち「親テーブルと子テーブルが 1 対 1 の関係性」であった場合はDELETEタグをつけるとエラーになりますWHERE <親テーブルの主キー> = <子テーブルの外部キー>WHERE <親テーブルの主キー> = <子テーブルの任意のカラム>


