### 12.18.7 JSON 模式验证函数

[](<>)

从 MySQL 8.0.17 开始，MySQL 支持针对符合以下标准的 JSON 模式验证 JSON 文档[JSON Schema 规范草案 4](https://json-schema.org/specification-links.html#draft-4).这可以使用本节中详述的任何一个函数来完成，这两个函数都有两个参数，一个 JSON 模式和一个根据模式验证的 JSON 文档。[`JSON_SCHEMA_VALID()`](json-validation-functions.html#function_json-schema-valid)如果文档对模式进行验证，则返回 true，否则返回 false；[`JSON_SCHEMA_VALIDATION_REPORT()`](json-validation-functions.html#function_json-schema-validation-report)提供 JSON 格式的验证报告。

这两个函数都处理空或无效输入，如下所示：

-   如果至少有一个论点是`空值`, 函数返回`空值`.

-   如果至少有一个参数不是有效的 JSON，则函数会引发错误 ([`ER_INVALID_TYPE_FOR_JSON`](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_invalid_type_for_json))

-   此外，如果架构不是有效的 JSON 对象，则函数返回[`ER_INVALID_JSON_TYPE`](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_invalid_json_type).

    MySQL 支持`必需的`JSON 模式中的属性以强制包含必需的属性（请参阅函数描述中的示例）。

    MySQL 支持`id`,`$模式`,`描述`， 和`类型`JSON 模式中的属性，但不需要任何这些。

    MySQL 不支持 JSON 模式中的外部资源；使用`$参考`关键词原因`JSON_SCHEMA_VALID()`失败[`ER_NOT_SUPPORTED_YET`](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_not_supported_yet).

笔记

MySQL 支持 JSON 模式中的正则表达式模式，它支持但默默地忽略无效模式（参见描述`JSON_SCHEMA_VALID()`例如）。

以下列表中详细描述了这些功能：

-   [](<>)

    [`JSON_SCHEMA_VALID(*`图式`*,*`文档`*)`](json-validation-functions.html#function_json-schema-valid)

    [](<>)

    验证 JSON*`文档`*针对 JSON*`图式`*.两个都*`图式`*和*`文档`*是必要的。架构必须是有效的 JSON 对象；该文档必须是有效的 JSON 文档。前提是满足这些条件： 如果文档根据模式验证，则函数返回 true (1)；否则，它返回 false (0)。

    在这个例子中，我们设置了一个用户变量`@schema`到地理坐标的 JSON 模式的值，以及另一个`@文档`到包含一个这样的坐标的 JSON 文档的值。然后我们验证`@文档`根据验证`@schema`通过使用它们作为参数`JSON_SCHEMA_VALID()`：

    ```
    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`包含`必需的`属性，我们可以设置`@文档`到一个在其他方面有效但不包含所需属性的值，然后对其进行测试`@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 模式，但没有`必需的`属性，`@文档`验证，因为它是一个有效的 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\_架构\_VALID() 和 CHECK 约束。**  `JSON_SCHEMA_VALID()`也可以用来强制`查看`约束。

    考虑表格`地理`如此处所示创建，带有一个 JSON 列`协调`表示地图上的经纬度点，由用作参数的 JSON 模式控制`JSON_SCHEMA_VALID()`作为表达式传递的调用`查看`对该表的约束：

    ```
    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`查看`约束不能包含对变量的引用，您必须将 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.html)陈述：

    ```
    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.
    ```

    在 MySQL 8.0.19 及更高版本中，您可以获得有关故障性质的精确信息——在这种情况下，`纬度`值超过了模式中定义的最大值——通过发出[`显示警告`](show-warnings.html)陈述：

    ```
    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)
    ```

    上面定义的第三个坐标值也是无效的，因为它缺少所需的`纬度`财产。和以前一样，您可以通过尝试将值插入`地理`表，然后发出`显示警告`然后：

    ```
    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 节，“检查约束”](create-table-check-constraints.html)， 了解更多信息。

    [](<>)

    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(*`图式`*,*`文档`*)`](json-validation-functions.html#function_json-schema-validation-report)

    [](<>)

    验证 JSON*`文档`*针对 JSON*`图式`*.两个都*`图式`*和*`文档`*是必要的。与 JSON 一样\_有效的\_SCHEMA()，架构必须是有效的 JSON 对象，文档必须是有效的 JSON 文档。如果满足这些条件，该函数会以 JSON 文档的形式返回关于验证结果的报告。如果 JSON 文档根据 JSON Schema 被认为是有效的，则该函数返回一个具有一个属性的 JSON 对象`有效的`具有“真”值。如果 JSON 文档验证失败，该函数将返回一个 JSON 对象，其中包括此处列出的属性：

    -   `有效的`：对于失败的架构验证，始终为“假”

    -   `原因`：包含失败原因的人类可读字符串

    -   `模式位置`：一个 JSON 指针 URI 片段标识符，指示在 JSON 模式中验证失败的位置（请参阅此列表后面的注释）

    -   `文件位置`：一个 JSON 指针 URI 片段标识符，指示在 JSON 文档中验证失败的位置（请参阅此列表后面的注释）

    -   `架构失败的关键字`: 一个字符串，包含违反的 JSON 模式中的关键字或属性的名称

    [](<>)

    笔记

    JSON 指针 URI 片段标识符定义在[RFC 6901 - JavaScript 对象表示法 (JSON) 指针](https://tools.ietf.org/html/rfc6901#page-5).（这些是*不是*与使用的 JSON 路径表示法相同[`JSON_EXTRACT()`](json-search-functions.html#function_json-extract)和其他 MySQL JSON 函数。）在这种表示法中，`#`代表整个文档，并且`#/myprop`表示包含在名为的顶级属性中的文档部分`我的道具`.有关详细信息，请参阅刚刚引用的规范和本节后面显示的示例。

    在这个例子中，我们设置了一个用户变量`@schema`到地理坐标的 JSON 模式的值，以及另一个`@文档`到包含一个这样的坐标的 JSON 文档的值。然后我们验证`@文档`根据验证`@schema`通过使用它们作为参数`JSON_SCHEMA_VALIDATION_REORT()`：

    ```
    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)
    ```

    现在我们设置`@文档`这样它就为其属性之一指定了非法值，如下所示：

    ```
    mysql> SET @document = '{
        '> "latitude": 63.444697,
        '> "longitude": 310.445118
        '> }';
    ```

    验证`@文档`现在在测试时失败`JSON_SCHEMA_VALIDATION_REPORT()`.函数调用的输出包含有关失败的详细信息（函数由[`JSON_PRETTY()`](json-utility-functions.html#function_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`包含`必需的`属性，我们可以设置`@文档`到一个在其他方面有效但不包含所需属性的值，然后对其进行测试`@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 模式，但没有`必需的`属性，`@文档`验证，因为它是一个有效的 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)
    ```
