文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手冊頁 (TGZ) - 258.5Kb
手冊頁 (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  JSON Schema 驗證函數

14.17.7 JSON Schema 驗證函數

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$schemadescriptiontype 屬性,但不需要其中任何一個。

MySQL 不支援 JSON 綱要中的外部資源;使用 $ref 關鍵字會導致 JSON_SCHEMA_VALID() 失敗並出現 ER_NOT_SUPPORTED_YET

注意

MySQL 支援 JSON 綱要中的正規表示式模式,它支援但不顯式忽略無效的模式 (請參閱 JSON_SCHEMA_VALID() 的描述以取得範例)。

以下清單中詳細說明了這些函數

  • JSON_SCHEMA_VALID(schema,document)

    根據 JSON schema 驗證 JSON documentschemadocument 都是必要的。綱要必須是有效的 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 驗證 JSON documentschemadocument 都是必要的。與 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)