MySQL 支援根據符合 JSON Schema 規格草案 4 的 JSON 綱要來驗證 JSON 文件。這可以使用本節中詳述的任一函數來完成,這兩個函數都接受兩個引數:一個 JSON 綱要和一個根據綱要驗證的 JSON 文件。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_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": "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 綱要,但沒有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_VALID()
呼叫中作為引數使用的 JSON 綱要管理,該呼叫會作為此資料表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 綱要內嵌傳遞至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.
您可以取得有關失敗性質的精確資訊 (在此案例中,
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
屬性。與之前一樣,您可以嘗試將值插入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 Schema 支援為字串指定正規表示式模式,但 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() 一樣,schema 必須是有效的 JSON 物件,而 document 必須是有效的 JSON 文件。在符合這些條件的前提下,此函式會傳回一份關於驗證結果的報告,其格式為 JSON 文件。如果根據 JSON Schema 認為 JSON 文件有效,則此函式會傳回一個 JSON 物件,其中包含一個屬性valid
,其值為 "true"。如果 JSON 文件驗證失敗,則此函式會傳回一個 JSON 物件,其中包含以下列出的屬性valid
:對於失敗的 schema 驗證,始終為 "false"reason
:一個人類可讀的字串,其中包含失敗的原因schema-location
:一個 JSON 指標 URI 片段識別符,指示 JSON schema 中驗證失敗的位置 (請參閱此列表之後的注意事項)document-location
:一個 JSON 指標 URI 片段識別符,指示 JSON 文件中驗證失敗的位置 (請參閱此列表之後的注意事項)schema-failed-keyword
:一個字串,其中包含 JSON schema 中被違反的關鍵字或屬性的名稱
注意JSON 指標 URI 片段識別符定義於 RFC 6901 - JavaScript 物件表示法 (JSON) 指標。(這些與
JSON_EXTRACT()
和其他 MySQL JSON 函式使用的 JSON 路徑表示法不同。) 在此表示法中,#
代表整個文件,而#/myprop
代表包含在名為myprop
的頂層屬性中的文件部分。有關更多資訊,請參閱剛引用的規格以及本節稍後顯示的範例。在此範例中,我們將使用者變數
@schema
設定為地理座標的 JSON schema 值,並將另一個變數@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 綱要,但沒有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)