MySQL 8.0.17 以降、MySQL では、「JSON スキーマ仕様のドラフト 4」に準拠する JSON スキーマに対する JSON ドキュメントの検証がサポートされます。 これは、このセクションで説明する関数のいずれかを使用して実行できます。どちらの関数も、JSON スキーマと、スキーマに対して検証される JSON ドキュメントの 2 つの引数を取ります。 JSON_SCHEMA_VALID()
は、ドキュメントがスキーマに対して検証される場合は true を返し、検証されない場合は false を返します。JSON_SCHEMA_VALIDATION_REPORT()
は、検証に関する JSON 形式のレポートを提供します。
どちらの関数も、次のように NULL または無効な入力を処理します:
少なくともいずれかの引数が
NULL
の場合、この関数はNULL
を戻します。少なくともいずれかの引数が有効な JSON でない場合、関数でエラーが発生します (
ER_INVALID_TYPE_FOR_JSON
)また、スキーマが有効な JSON オブジェクトでない場合、関数は
ER_INVALID_JSON_TYPE
を戻します。
MySQL では、JSON スキーマの required
属性をサポートして、必要なプロパティを強制的に含めることができます (関数の説明の例を参照)。
MySQL では、JSON スキーマの id
, $schema
, description
および type
属性がサポートされていますが、これらは必要ありません。
MySQL では、JSON スキーマの外部リソースはサポートされていません。$ref
キーワードを使用すると、JSON_SCHEMA_VALID()
が ER_NOT_SUPPORTED_YET
で失敗します。
MySQL では、JSON スキーマの正規表現パターンがサポートされています。JSON スキーマでは、無効なパターンはサポートされますが、暗黙的に無視されます (例は、JSON_SCHEMA_VALID()
の説明を参照)。
これらの関数の詳細は、次のリストを参照してください:
-
JSON_SCHEMA_VALID(
schema
,document
)JSON
schema
に対して JSONdocument
を検証します。schema
とdocument
の両方が必要です。 スキーマは有効な JSON オブジェクトである必要があります。ドキュメントは有効な JSON ドキュメントである必要があります。 これらの条件が満たされている場合: ドキュメントがスキーマに対して検証される場合、関数は true (1) を戻し、それ以外の場合は false (0) を戻します。この例では、ユーザー変数
@schema
を地理座標の JSON スキーマの値に設定し、別の@document
をその座標を含む JSON ドキュメントの値に設定します。 次に、JSON_SCHEMA_VALID()
の引数として使用して、@document
が@schema
に従って検証されることを確認します:mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> }, '> "required": ["latitude", "longitude"] '>}'; Query OK, 0 rows affected (0.01 sec) mysql> SET @document = '{ '> "latitude": 63.444697, '> "longitude": 10.445118 '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALID(@schema, @document); +---------------------------------------+ | JSON_SCHEMA_VALID(@schema, @document) | +---------------------------------------+ | 1 | +---------------------------------------+ 1 row in set (0.00 sec)
@schema
にはrequired
属性が含まれているため、@document
を、それ以外は有効だが必須プロパティを含まない値に設定し、次のように@schema
に対してテストできます:mysql> SET @document = '{}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALID(@schema, @document); +---------------------------------------+ | JSON_SCHEMA_VALID(@schema, @document) | +---------------------------------------+ | 0 | +---------------------------------------+ 1 row in set (0.00 sec)
次に示すように、
@schema
の値を同じ JSON スキーマに設定し、required
属性を指定しない場合、@document
は、プロパティが含まれていなくても有効な JSON オブジェクトであるため検証します:mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> } '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALID(@schema, @document); +---------------------------------------+ | JSON_SCHEMA_VALID(@schema, @document) | +---------------------------------------+ | 1 | +---------------------------------------+ 1 row in set (0.00 sec)
JSON_SCHEMA_VALID() および CHECK 制約.
JSON_SCHEMA_VALID()
を使用して、CHECK
制約を施行することもできます。次のように作成されたテーブル
geo
について考えてみます。JSON カラムcoordinate
は、このテーブルのCHECK
制約の式として渡されるJSON_SCHEMA_VALID()
コールで引数として使用される JSON スキーマによって制御される、マップ上の緯度と経度の点を表します:mysql> CREATE TABLE geo ( -> coordinate JSON, -> CHECK( -> JSON_SCHEMA_VALID( -> '{ '> "type":"object", '> "properties":{ '> "latitude":{"type":"number", "minimum":-90, "maximum":90}, '> "longitude":{"type":"number", "minimum":-180, "maximum":180} '> }, '> "required": ["latitude", "longitude"] '> }', -> coordinate -> ) -> ) -> ); Query OK, 0 rows affected (0.45 sec)
注記MySQL
CHECK
制約には変数への参照を含めることができないため、JSON スキーマを使用してテーブルにこのような制約を指定する場合は、JSON スキーマをJSON_SCHEMA_VALID()
インラインに渡す必要があります。座標を表す JSON 値を次の 3 つの変数に割り当てます:
mysql> SET @point1 = '{"latitude":59, "longitude":18}'; Query OK, 0 rows affected (0.00 sec) mysql> SET @point2 = '{"latitude":91, "longitude":0}'; Query OK, 0 rows affected (0.00 sec) mysql> SET @point3 = '{"longitude":120}'; Query OK, 0 rows affected (0.00 sec)
次の
INSERT
ステートメントに示すように、これらの最初の値は有効です:mysql> INSERT INTO geo VALUES(@point1); Query OK, 1 row affected (0.05 sec)
2 番目の JSON 値は無効であるため、次に示すように制約は失敗します:
mysql> INSERT INTO geo VALUES(@point2); ERROR 3819 (HY000): Check constraint 'geo_chk_1' is violated.
MySQL 8.0.19 以降では、障害の性質に関する正確な情報を取得できます。この場合、
latitude
値がSHOW WARNINGS
ステートメントの発行によってスキーマで定義された最大値を超えています:mysql> SHOW WARNINGS\G *************************** 1. row *************************** Level: Error Code: 3934 Message: The JSON document location '#/latitude' failed requirement 'maximum' at JSON Schema location '#/properties/latitude'. *************************** 2. row *************************** Level: Error Code: 3819 Message: Check constraint 'geo_chk_1' is violated. 2 rows in set (0.00 sec)
必要な
latitude
プロパティがないため、前述の 3 番目の座標値も無効です。 以前と同様に、geo
テーブルに値を挿入してから、SHOW WARNINGS
を発行することで、これを確認できます:mysql> INSERT INTO geo VALUES(@point3); ERROR 3819 (HY000): Check constraint 'geo_chk_1' is violated. mysql> SHOW WARNINGS\G *************************** 1. row *************************** Level: Error Code: 3934 Message: The JSON document location '#' failed requirement 'required' at JSON Schema location '#'. *************************** 2. row *************************** Level: Error Code: 3819 Message: Check constraint 'geo_chk_1' is violated. 2 rows in set (0.00 sec)
詳しくはセクション13.1.20.6「CHECK 制約」,をご覧ください。
JSON スキーマでは、文字列の正規表現パターンの指定がサポートされていますが、MySQL で使用される実装では、無効なパターンは暗黙的に無視されます。 つまり、次に示すように、正規表現パターンが無効な場合でも、
JSON_SCHEMA_VALID()
は true を返すことができます:mysql> SELECT JSON_SCHEMA_VALID('{"type":"string","pattern":"("}', '"abc"'); +---------------------------------------------------------------+ | JSON_SCHEMA_VALID('{"type":"string","pattern":"("}', '"abc"') | +---------------------------------------------------------------+ | 1 | +---------------------------------------------------------------+ 1 row in set (0.04 sec)
-
JSON_SCHEMA_VALIDATION_REPORT(
schema
,document
)JSON
schema
に対して JSONdocument
を検証します。schema
とdocument
の両方が必要です。 JSON_VALID_SCHEMA() と同様に、スキーマは有効な JSON オブジェクトである必要があり、ドキュメントは有効な JSON ドキュメントである必要があります。 これらの条件が満たされている場合、関数は検証の結果に関するレポートを JSON ドキュメントとして返します。 JSON スキーマに従って JSON ドキュメントが有効とみなされる場合、この関数は、値が true のプロパティvalid
を持つ JSON オブジェクトを戻します。 JSON ドキュメントが検証に失敗した場合、この関数は、次に示すプロパティを含む JSON オブジェクトを返します:valid
: スキーマ検証に失敗した場合は常に falsereason
: 失敗の理由を含む判読可能な文字列schema-location
: JSON スキーマ内で検証が失敗した場所を示す JSON ポインタ URI フラグメント識別子 (このリストの後のノートを参照)document-location
: JSON ドキュメント内で検証が失敗した場所を示す JSON ポインタ URI フラグメント識別子 (このリストの後のノートを参照)schema-failed-keyword
: 違反があった JSON スキーマ内のキーワードまたはプロパティの名前を含む文字列
注記JSON ポインタ URI フラグメント識別子は、「RFC 6901 - JavaScript Object Notation (JSON) ポインタ」で定義されます。 (これらは、
JSON_EXTRACT()
および他の MySQL JSON 関数で使用される JSON パス表記とは異なります。) この表記法では、#
はドキュメント全体を表し、#/myprop
はmyprop
という最上位プロパティに含まれるドキュメントの一部を表します。 詳細は、前述の仕様と、このセクションで後述する例を参照してください。この例では、ユーザー変数
@schema
を地理座標の JSON スキーマの値に設定し、別の@document
をその座標を含む JSON ドキュメントの値に設定します。 次に、JSON_SCHEMA_VALIDATION_REORT()
の引数として使用して、@document
が@schema
に従って検証されることを確認します:mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> }, '> "required": ["latitude", "longitude"] '>}'; Query OK, 0 rows affected (0.01 sec) mysql> SET @document = '{ '> "latitude": 63.444697, '> "longitude": 10.445118 '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALIDATION_REPORT(@schema, @document); +---------------------------------------------------+ | JSON_SCHEMA_VALIDATION_REPORT(@schema, @document) | +---------------------------------------------------+ | {"valid": true} | +---------------------------------------------------+ 1 row in set (0.00 sec)
次に示すように、いずれかのプロパティに不正な値が指定されるように
@document
を設定します:mysql> SET @document = '{ '> "latitude": 63.444697, '> "longitude": 310.445118 '> }';
JSON_SCHEMA_VALIDATION_REPORT()
でテストすると、@document
の検証が失敗するようになりました。 関数コールからの出力には、次に示すように、失敗に関する詳細情報が含まれます (より適切な書式設定を提供するためにJSON_PRETTY()
でラップされた関数を使用):mysql> SELECT JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document))\G *************************** 1. row *************************** JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document)): { "valid": false, "reason": "The JSON document location '#/longitude' failed requirement 'maximum' at JSON Schema location '#/properties/longitude'", "schema-location": "#/properties/longitude", "document-location": "#/longitude", "schema-failed-keyword": "maximum" } 1 row in set (0.00 sec)
@schema
にはrequired
属性が含まれているため、@document
を、それ以外は有効だが必須プロパティを含まない値に設定してから、@schema
に対してテストできます。JSON_SCHEMA_VALIDATION_REPORT()
の出力は、次のように、必要な要素がないために検証が失敗することを示しています:mysql> SET @document = '{}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document))\G *************************** 1. row *************************** JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document)): { "valid": false, "reason": "The JSON document location '#' failed requirement 'required' at JSON Schema location '#'", "schema-location": "#", "document-location": "#", "schema-failed-keyword": "required" } 1 row in set (0.00 sec)
次に示すように、
@schema
の値を同じ JSON スキーマに設定し、required
属性を指定しない場合、@document
は、プロパティが含まれていなくても有効な JSON オブジェクトであるため検証します:mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> } '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALIDATION_REPORT(@schema, @document); +---------------------------------------------------+ | JSON_SCHEMA_VALIDATION_REPORT(@schema, @document) | +---------------------------------------------------+ | {"valid": true} | +---------------------------------------------------+ 1 row in set (0.00 sec)