文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (美式 Letter) - 40.0Mb
PDF (A4) - 40.1Mb
手冊頁 (TGZ) - 258.2Kb
手冊頁 (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


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

14.17.7 JSON Schema 驗證函數

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$schemadescriptiontype 屬性,但不要求這些屬性。

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

注意

MySQL 支援 JSON Schema 中的正規表達式模式,該模式支援但會靜默忽略無效模式 (請參閱 JSON_SCHEMA_VALID() 的描述,以取得範例)。

下列清單會詳細描述這些函數

  • JSON_SCHEMA_VALID(schema,document)

    針對 JSON schema 驗證 JSON documentschemadocument 都是必要的。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 驗證 JSON documentschemadocument 都是必要的。與 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)