### 12.18.6 JSON 表函数

本节包含有关将 JSON 数据转换为表格数据的 JSON 函数的信息。MySQL 8.0 支持这样一种功能，`JSON_TABLE()`.

[](<>) [`JSON_TABLE(*`表达式`*, *`小路`* 列 （*`列列表`*） [作为] *`别名`*)`](json-table-functions.html#function_json-table)

[](<>)

从 JSON 文档中提取数据并将其作为具有指定列的关系表返回。此函数的完整语法如下所示：

```
JSON_TABLE(
    expr,
    path COLUMNS (column_list)
)   [AS] alias

column_list:
    column[, column][, ...]

column:
    name FOR ORDINALITY
    |  name type PATH string path [on_empty] [on_error]
    |  name type EXISTS PATH string path
    |  NESTED [PATH] path COLUMNS (column_list)

on_empty:
    {NULL | DEFAULT json_string | ERROR} ON EMPTY

on_error:
    {NULL | DEFAULT json_string | ERROR} ON ERROR
```

*`表达式`*：这是一个返回 JSON 数据的表达式。这可以是一个常数 (`'{"a":1}'`), 一列 (`t1.json_data`，给定表`t1`之前指定`JSON_TABLE()`在里面`从`子句），或函数调用（`JSON_EXTRACT(t1.json_data,'$.post.comments')`）。

*`路径`*：应用于数据源的JSON路径表达式。我们将与路径匹配的JSON值称为*行源*; 这用于生成一行关系数据。这个`柱`子句计算行源，在行源中查找特定的JSON值，并将这些JSON值作为SQL值返回到一行关系数据的各个列中。

这个*`别名`*是必需的。表别名的常规规则适用（请参见[第9.2节，“模式对象名称”](identifiers.html)).

从MySQL 8.0.27开始，该函数以不区分大小写的方式比较列名。

`JSON_表（）`支持以下列表中描述的四种类型的列：

1.  `*`名称`*为了平凡`：此类型枚举中的行`柱`条款名为*`名称`*是一个类型为`无符号整数`，其初始值为1。这相当于将列指定为`自动增量`在一个[`创建表格`](create-table.html)语句，并可用于区分由`嵌套的[路径]`条款

2.  `*`名称`* *`类型`*路径*`字符串路径`* [*`空荡荡的`*] [*`论错误`*]`：此类型的列用于提取*`字符串路径`*. *`类型`*是MySQL标量数据类型（也就是说，它不能是对象或数组）。`JSON_表（）`将数据提取为JSON，然后使用MySQL中应用于JSON数据的常规自动类型转换将其强制为列类型。缺少值会触发*`空荡荡的`*条款保存对象或数组会触发可选的*`论错误`*条款在将保存为JSON的值强制转换为表列（例如试图保存字符串）期间发生错误时，也会发生这种情况`“自闭症”`到整数列。

3.  `*`名称`* *`类型`*存在路径*`路径`*`：如果在指定的位置存在任何数据，则此列返回1*`路径`*，否则为0。*`类型`*可以是任何有效的MySQL数据类型，但通常应指定为[`国际的`](integer-types.html).

4.  `嵌套的[路径]*`路径`*纵队(*`列列表`*)`：这会将JSON数据中的嵌套对象或数组与父对象或数组中的JSON值一起放在一行中。使用多个`路径`选项允许将JSON值从多个嵌套级别投影到一行中。

    这个*`路径`*相对于行路径的父路径`JSON_表（）`，或父对象的路径`嵌套的[路径]`在嵌套路径的情况下。

*`空荡荡的`*，如果指定，则确定`JSON_表（）`在数据丢失时执行（取决于类型）。此子句也会在中的列上触发`嵌套路径`当后者没有匹配项且`无效的`为它生成了一行。*`空荡荡的`*采用以下值之一：

-   `空时为空`：该列设置为`无效的`; 这是默认行为。

-   `违约*`json\_字符串`*空荡荡的`：提供的*`json_字符串`*被解析为JSON，只要它是有效的，并存储而不是缺少的值。列类型规则也适用于默认值。

-   `空时出错`：抛出一个错误。

    如果使用，*`论错误`*获取以下值之一，并获得如下所示的相应结果：

-   `错误时为空`：该列设置为`无效的`; 这是默认行为。

-   `违约*`json字符串`*论错误`当前位置*`json_字符串`*被解析为JSON（前提是它有效）并存储，而不是对象或数组。

-   `一个接一个的错误`：抛出一个错误。

    在MySQL 8.0.20之前，如果出现类型转换错误，则会引发警告`错误时为空`或`违约论错误`被指定或暗示。在MySQL 8.0.20及更高版本中，情况不再如此。（错误#30628330）

    以前，可以指定`空荡荡的`和`论错误`按任意顺序排列的子句。这与SQL标准背道而驰，后者规定`空荡荡的`，如果指定，则必须在任何`论错误`条款因此，从MySQL 8.0.20开始`论错误`之前`空荡荡的`不赞成；尝试这样做会导致服务器发出警告。在MySQL的未来版本中，对非标准语法的支持将被删除。

    当保存到列中的值被截断时，例如将3.14159保存到[`十进制（10,1）`](fixed-point-types.html)列中，将独立于任何`论错误`选项当在一条语句中截断多个值时，只发出一次警告。

    在MySQL 8.0.21之前，当传递给该函数的表达式和路径解析为JSON null时，`JSON_表（）`提出了一个错误。在MySQL 8.0.21及更高版本中，它返回SQL`无效的`在这种情况下，根据SQL标准，如下所示（Bug#31345503，Bug#99557）：


```
mysql> SELECT *
    ->   FROM
    ->     JSON_TABLE(
    ->       '[ {"c1": null} ]',
    ->       '$[*]' COLUMNS( c1 INT PATH '$.c1' ERROR ON ERROR )
    ->     ) as jt;
+------+
| c1   |
+------+
| NULL |
+------+
1 row in set (0.00 sec)
```

下面的查询演示了`空荡荡的`和`论错误`.对应于`{“b”：1}`这条路是空的`“$a”`，并试图保存`[1,2]`当标量产生错误时；这些行在显示的输出中高亮显示。

```
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[{"a":"3"},{"a":2},{"b":1},{"a":0},{"a":[1,2]}]',
    ->     "$[*]"
    ->     COLUMNS(
    ->       rowid FOR ORDINALITY,
    ->       ac VARCHAR(100) PATH "$.a" DEFAULT '111' ON EMPTY DEFAULT '999' ON ERROR,
    ->       aj JSON PATH "$.a" DEFAULT '{"x": 333}' ON EMPTY,
    ->       bx INT EXISTS PATH "$.b"
    ->     )
    ->   ) AS tt;

+-------+------+------------+------+
| rowid | ac   | aj         | bx   |
+-------+------+------------+------+
|     1 | 3    | "3"        |    0 |
|     2 | 2    | 2          |    0 |
|     3 | 111  | {"x": 333} |    1 |
|     4 | 0    | 0          |    0 |
|     5 | 999  | [1, 2]     |    0 |
+-------+------+------------+------+
5 rows in set (0.00 sec)
```

列名受制于管理表列名的常规规则和限制。看见[第9.2节，“模式对象名称”](identifiers.html).

检查所有JSON和JSON路径表达式的有效性；任何一种类型的无效表达式都会导致错误。

每一场比赛*`路径`*在`柱`关键字映射到结果表中的单个行。例如，以下查询给出的结果如下所示：

```
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[{"x":2,"y":"8"},{"x":"3","y":"7"},{"x":"4","y":6}]',
    ->     "$[*]" COLUMNS(
    ->       xval VARCHAR(100) PATH "$.x",
    ->       yval VARCHAR(100) PATH "$.y"
    ->     )
    ->   ) AS  jt1;

+------+------+
| xval | yval |
+------+------+
| 2    | 8    |
| 3    | 7    |
| 4    | 6    |
+------+------+
```

表情`"$[*]"`匹配数组的每个元素。可以通过修改路径来过滤结果中的行。例如，使用`"$[1]"`将提取限制为用作源的JSON数组的第二个元素，如下所示：

```
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[{"x":2,"y":"8"},{"x":"3","y":"7"},{"x":"4","y":6}]',
    ->     "$[1]" COLUMNS(
    ->       xval VARCHAR(100) PATH "$.x",
    ->       yval VARCHAR(100) PATH "$.y"
    ->     )
    ->   ) AS  jt1;

+------+------+
| xval | yval |
+------+------+
| 3    | 7    |
+------+------+
```

在列定义中，`"$"`将整个匹配传递给列；`“$.x”`和`“$y”`仅传递与键对应的值`十、`和`y`在那场比赛中。有关更多信息，请参阅[JSON路径语法](json.html#json-path-syntax).

`嵌套路径`（或者干脆`嵌套的`; `路径`是可选的）为中的每个匹配生成一组记录`柱`它所属的条款。如果不匹配，嵌套路径的所有列都将设置为`无效的`。这将在最顶端的子句和`嵌套的[路径]`。可以通过在中应用适当的条件来模拟内部联接`哪里`子句，如下所示：

```
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[ {"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3}]',
    ->     '$[*]' COLUMNS(
    ->             a INT PATH '$.a',
    ->             NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$')
    ->            )
    ->    ) AS jt
    -> WHERE b IS NOT NULL;

+------+------+
| a    | b    |
+------+------+
|    1 |   11 |
|    1 |  111 |
|    2 |   22 |
|    2 |  222 |
+------+------+
```

同级嵌套路径，即两个或多个`嵌套的[路径]`同时`柱`子句一次一个接一个地处理。当一个嵌套路径生成记录时，任何同级嵌套路径表达式的列都设置为`无效的`。这意味着在一个包含`柱`子句是生成的所有记录的总和，而不是乘积`嵌套的[路径]`修饰符，如下所示：

```
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}]',
    ->     '$[*]' COLUMNS(
    ->         a INT PATH '$.a',
    ->         NESTED PATH '$.b[*]' COLUMNS (b1 INT PATH '$'),
    ->         NESTED PATH '$.b[*]' COLUMNS (b2 INT PATH '$')
    ->     )
    -> ) AS jt;

+------+------+------+
| a    | b1   | b2   |
+------+------+------+
|    1 |   11 | NULL |
|    1 |  111 | NULL |
|    1 | NULL |   11 |
|    1 | NULL |  111 |
|    2 |   22 | NULL |
|    2 |  222 | NULL |
|    2 | NULL |   22 |
|    2 | NULL |  222 |
+------+------+------+
```

A.`为了平凡`列枚举由`柱`子句，并可用于区分嵌套路径的父记录，尤其是当父记录中的值相同时，如图所示：

```
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[{"a": "a_val",
    '>       "b": [{"c": "c_val", "l": [1,2]}]},
    '>     {"a": "a_val",
    '>       "b": [{"c": "c_val","l": [11]}, {"c": "c_val", "l": [22]}]}]',
    ->     '$[*]' COLUMNS(
    ->       top_ord FOR ORDINALITY,
    ->       apath VARCHAR(10) PATH '$.a',
    ->       NESTED PATH '$.b[*]' COLUMNS (
    ->         bpath VARCHAR(10) PATH '$.c',
    ->         ord FOR ORDINALITY,
    ->         NESTED PATH '$.l[*]' COLUMNS (lpath varchar(10) PATH '$')
    ->         )
    ->     )
    -> ) as jt;

+---------+---------+---------+------+-------+
| top_ord | apath   | bpath   | ord  | lpath |
+---------+---------+---------+------+-------+
|       1 |  a_val  |  c_val  |    1 | 1     |
|       1 |  a_val  |  c_val  |    1 | 2     |
|       2 |  a_val  |  c_val  |    1 | 11    |
|       2 |  a_val  |  c_val  |    2 | 22    |
+---------+---------+---------+------+-------+
```

源文档包含两个元素的数组；每个元素产生两行。价值观`阿帕斯`和`B路径`在整个结果集中是相同的；这意味着它们不能用于确定`lpath`价值观来自相同或不同的父母。价值`奥德`列与具有`头条`等于1，所以这两个值来自单个对象。其余两个值来自不同的对象，因为它们在`奥德`柱

通常，不能联接依赖于同一个表中前面表的列的派生表`从…起`条款根据SQL标准，MySQL对表函数例外；这些表被认为是横向派生表，即使在MySQL版本中，这些表还不支持`侧面的`关键词（8.0.13及更早版本）。在哪个版本`侧面的`是受支持的（8.0.14及更高版本），它是隐式的，因此以前是不允许的`JSON_表（）`，也符合标准。

假设你有一张桌子`t1`使用以下语句创建和填充：

```
CREATE TABLE t1 (c1 INT, c2 CHAR(1), c3 JSON);

INSERT INTO t1 () VALUES
	ROW(1, 'z', JSON_OBJECT('a', 23, 'b', 27, 'c', 1)),
	ROW(1, 'y', JSON_OBJECT('a', 44, 'b', 22, 'c', 11)),
	ROW(2, 'x', JSON_OBJECT('b', 1, 'c', 15)),
	ROW(3, 'w', JSON_OBJECT('a', 5, 'b', 6, 'c', 7)),
	ROW(5, 'v', JSON_OBJECT('a', 123, 'c', 1111))
;
```

然后可以执行连接，比如这个连接`JSON_表（）`充当派生表，同时引用以前引用的表中的列：

```
SELECT c1, c2, JSON_EXTRACT(c3, '$.*')
FROM t1 AS m
JOIN
JSON_TABLE(
  m.c3,
  '$.*'
  COLUMNS(
    at VARCHAR(10) PATH '$.a' DEFAULT '1' ON EMPTY,
    bt VARCHAR(10) PATH '$.b' DEFAULT '2' ON EMPTY,
    ct VARCHAR(10) PATH '$.c' DEFAULT '3' ON EMPTY
  )
) AS tt
ON m.c1 > tt.at;
```

试图使用`侧面的`带有此查询的关键字将引发[`ER_解析_错误`](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_parse_error).
