Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 Reference Manual  /  ...  /  JSON Schema Validation Functions

14.17.7 JSON 模式验证函数

MySQL 支持根据 JSON 模式对 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

Note

MySQL 支持 JSON 模式中的正则表达式模式,支持但忽略无效的模式(请参阅 JSON_SCHEMA_VALID() 的描述以获取示例)。

这些函数在以下列表中有详细描述:

  • JSON_ SCHEMA_VALID(schema,document)

    验证 JSON document 对 JSON schema。 both schemadocument 都是必需的。schema 必须是一个有效的 JSON 对象;document 必须是一个有效的 JSON 文档。如果文档验证通过 schema,函数返回 true(1);否则,返回 false(0)。

    在这个示例中,我们将用户变量@schema设置为一个用于地理坐标的 JSON 模式,并将另一个变量@document设置为包含一个这样的坐标的 JSON 文档。然后,我们使用它们作为参数来验证@document是否符合@schema,如下所示:

    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包含了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": "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_SCHEMA_VALID() 和 CHECK 约束. JSON_SCHEMA_VALID()也可以用来强制CHECK约束。

    考虑创建的表geo,其中包含一个 JSON 列coordinate,表示地图上的 latitude 和 longitude 点,该列由在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)
    Note

    由于 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.

    您可以通过发出SHOW WARNINGS语句来获取关于失败的精确信息——在这个例子中,latitude 值超过了 schema 中定义的最大值:

    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)

    请参阅Section 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)

    验证一个JSONdocument对应一个JSONschema。两个schemadocument都是必需的。与JSON_VALID_ SCHEMA()相同,schema必须是一个有效的JSON对象,document必须是一个有效的JSON文档。如果满足这些条件,该函数将返回一个验证结果报告作为一个JSON文档。如果根据JSON Schema认为JSON文档是有效的,该函数将返回一个JSON对象,其中包含一个名为valid的属性,并且该值为“true”。如果JSON文档失败验证,该函数将返回一个JSON对象,其中包含以下属性:

    • valid: 对于失败的schema验证总是“false”

    • reason: 包含失败原因的可读人字符串

    • schema-location: 指示JSON schema中验证失败的位置的JSON指针URI片段标识符(见以下注释)

    • document-location: 指示JSON文档中验证失败的位置的JSON指针URI片段标识符(见以下注释)

    • schema-failed-keyword: 包含在JSON schema中违反的关键字或属性名称的字符串

    Note

    JSON 指针 URI 片段标识符在 RFC 6901 - JavaScript Object Notation (JSON) Pointer 中定义。(这与 MySQL JSON 函数 JSON_EXTRACT() 和其他 MySQL JSON 函数使用的 JSON 路径 notation 不同。) 在这个notation中,# 表示整个文档,而 #/myprop 表示文档中的顶级属性名为 myprop 的部分。请参阅上述引用和本节后面的示例以获取更多信息。

    在这个示例中,我们将用户变量 @schema 设置为地理坐标的 JSON 模式,并将另一个变量 @document 设置为包含一个这样的坐标的 JSON 文档。然后,我们使用它们作为参数来验证 @document 是否符合 @schema,通过调用 JSON_ SCHEMA_VALIDATION_REPORT():

    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)

    现在,我们将 @document 设置为其中一个属性的非法值,如下所示:

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

    验证 @document 现在失败,当使用 JSON_SCHEMA_VALIDATION_REPORT() 测试时。函数调用结果包含详细的失败信息(使用 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设置为一个有效的JSON对象,但不包含所需的属性,然后将其与@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": "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)