MySQL 支援針對符合 JSON Schema 規格草案 4 的 JSON Schema 驗證 JSON 文件。這可以使用本節詳述的任一函數完成,這兩個函數都採用兩個引數:JSON Schema 和針對該 Schema 驗證的 JSON 文件。如果文件通過 Schema 驗證,則 JSON_SCHEMA_VALID()
會傳回 true,如果沒有,則傳回 false;JSON_SCHEMA_VALIDATION_REPORT()
提供 JSON 格式的驗證報告。
兩個函數都以下列方式處理 null 或無效的輸入
如果至少有一個引數是
NULL
,函數會傳回NULL
。如果至少有一個引數不是有效的 JSON,函數會引發錯誤 (
ER_INVALID_TYPE_FOR_JSON
)此外,如果 Schema 不是有效的 JSON 物件,則函數會傳回
ER_INVALID_JSON_TYPE
。
MySQL 支援 JSON Schema 中的 required
屬性,以強制包含必要的屬性 (請參閱函數描述中的範例)。
MySQL 支援 JSON Schema 中的 id
、$schema
、description
和 type
屬性,但不要求這些屬性。
MySQL 不支援 JSON Schema 中的外部資源;使用 $ref
關鍵字會導致 JSON_SCHEMA_VALID()
失敗並顯示 ER_NOT_SUPPORTED_YET
。
MySQL 支援 JSON Schema 中的正規表達式模式,該模式支援但會靜默忽略無效模式 (請參閱 JSON_SCHEMA_VALID()
的描述,以取得範例)。
下列清單會詳細描述這些函數
JSON_SCHEMA_VALID(
schema
,document
)針對 JSON
schema
驗證 JSONdocument
。schema
和document
都是必要的。Schema 必須是有效的 JSON 物件;文件必須是有效的 JSON 文件。在符合這些條件的前提下:如果文件通過 Schema 驗證,則函數會傳回 true (1);否則,會傳回 false (0)。在本範例中,我們將使用者變數
@schema
設定為地理座標的 JSON Schema 值,並將另一個使用者變數@document
設定為包含一個此類座標的 JSON 文件值。然後,我們使用它們作為JSON_SCHEMA_VALID()
的引數,來驗證@document
是否根據@schema
進行驗證mysql> SET @schema = '{ '> "id": "https://json-schema.dev.org.tw/geo", '> "$schema": "https://json-schema.dev.org.tw/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 Schema,但沒有required
屬性,則@document
會通過驗證,因為它是有效的 JSON 物件,即使它不包含任何屬性,如此處所示mysql> SET @schema = '{ '> "id": "https://json-schema.dev.org.tw/geo", '> "$schema": "https://json-schema.dev.org.tw/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
代表地圖上的經度和緯度點,由 JSON Schema 管理,該 Schema 用作JSON_SCHEMA_VALID()
呼叫中的引數,該呼叫會作為此資料表上CHECK
限制的表達式傳遞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 Schema 行內傳遞至JSON_SCHEMA_VALID()
。我們將代表座標的 JSON 值指派給三個變數,如此處所示
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)
第二個 JSON 值無效,因此無法通過限制,如此處所示
mysql> INSERT INTO geo VALUES(@point2); ERROR 3819 (HY000): Check constraint 'geo_chk_1' is violated.
您可以使用
SHOW WARNINGS
語句,取得關於失敗本質的精確資訊,在此案例中,即latitude
值超過了綱要中定義的最大值。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
屬性。和之前一樣,您可以嘗試將此值插入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)
更多資訊請參閱 第 15.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 文件有效,此函數會傳回一個具有一個名為valid
屬性的 JSON 物件,其值為「true」。如果 JSON 文件驗證失敗,此函數會傳回一個 JSON 物件,其中包含此處列出的屬性。valid
:對於失敗的綱要驗證,值永遠為「false」。reason
:包含失敗原因的人類可讀字串。schema-location
:JSON 指標 URI 片段識別碼,指示 JSON 綱要中驗證失敗的位置(請參閱此列表後面的注意事項)。document-location
:JSON 指標 URI 片段識別碼,指示 JSON 文件中驗證失敗的位置(請參閱此列表後面的注意事項)。schema-failed-keyword
:包含 JSON 綱要中被違反的關鍵字或屬性名稱的字串。
注意JSON 指標 URI 片段識別碼在 RFC 6901 - JavaScript 物件表示法 (JSON) 指標 中定義。(它們與
JSON_EXTRACT()
和其他 MySQL JSON 函數使用的 JSON 路徑表示法不同。)在此表示法中,#
代表整個文件,而#/myprop
代表文件中包含在名為myprop
的最上層屬性中的部分。更多資訊請參閱剛剛引用的規範和本節稍後顯示的範例。在此範例中,我們將使用者變數
@schema
設定為地理座標的 JSON 綱要值,並將另一個使用者變數@document
設定為包含一個此類座標的 JSON 文件值。然後,我們使用它們作為JSON_SCHEMA_VALIDATION_REORT()
的引數,驗證@document
是否根據@schema
進行驗證。mysql> SET @schema = '{ '> "id": "https://json-schema.dev.org.tw/geo", '> "$schema": "https://json-schema.dev.org.tw/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 Schema,但沒有required
屬性,則@document
會通過驗證,因為它是有效的 JSON 物件,即使它不包含任何屬性,如此處所示mysql> SET @schema = '{ '> "id": "https://json-schema.dev.org.tw/geo", '> "$schema": "https://json-schema.dev.org.tw/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)