解压 JSON 列 SQL Server 2019 中的所有数组

Unpack all arrays in a JSON column SQL Server 2019

假设我有一个 table Schema.table 包含这些列

id | json_col

在表格上,例如

id=1
json_col ={"names":["John","Peter"],"ages":["31","40"]}

namesages 的长度始终相等,但可能因 id 而异(大小至少为 1,但没有上限)。

我们如何得到一个“展开的”table - table 每个“名字”、“年龄”都有一行,例如

id | names | ages 
---+-------+------
 1 | John  | 31
 1 | Peter | 41
 2 | Jim   | 17
 3 | Foo   |  2
.
.

我试过 OPENJSON 和 CROSS APPLY 但下面给出了 namesages 的任意组合,这是不正确的,因此我之后需要进行大量过滤

SELECT *
FROM Schema.table
CROSS APPLY OPENJSON(Schema.table,'$.names')
CROSS APPLY OPENJSON(Schema.table,'$.ages')

可能会使用条件聚合以及应用 CROSS APPLY

SELECT id, 
       MAX(CASE WHEN RowKey = 'names' THEN value END) AS names,
       MAX(CASE WHEN RowKey = 'ages' THEN value END) AS ages
  FROM
  (
   SELECT id, Q0.[value] AS RowArray, Q0.[key] AS RowKey
     FROM tab
    CROSS APPLY OPENJSON(JsonCol) AS Q0
  ) r
 CROSS APPLY OPENJSON(r.RowArray) v
 GROUP BY id, v.[key]   
 ORDER BY id, v.[key]

 id | names | ages 
 ---+-------+------
  1 | John  | 31
  1 | Peter | 41
  2 | Jim   | 17
  3 | Foo   |  2

Demo

OPENJSON 的第一个参数是 JSON 列值,而不是 table 本身

这是我的建议

DECLARE @tbl TABLE(id INT,json_col NVARCHAR(MAX));
INSERT INTO @tbl VALUES(1,N'{"names":["John","Peter"],"ages":["31","40"]}')
                      ,(2,N'{"names":["Jim"],"ages":["17"]}');

SELECT t.id
      ,B.[key] As ValueIndex
      ,B.[value] AS PersonNam
      ,JSON_VALUE(A.ages,CONCAT('$[',B.[key],']')) AS PersonAge
FROM @tbl t
CROSS APPLY OPENJSON(t.json_col) 
            WITH(names NVARCHAR(MAX) AS JSON
                ,ages  NVARCHAR(MAX) AS JSON) A
CROSS APPLY OPENJSON(A.names) B;

简而言之:

  • 我们使用带有 WITH 子句的 OPENJSON 来将 namesages 读入新的 json 变量。
  • 我们再用一个OPENJSON来“爆破”names-array
  • 由于key是数值在数组中的位置,我们可以使用JSON_VALUE()来读取对应的age-value的位置。

一般性评论:如果此 JSON 在您的控制之下,您应该将其更改为 entity-centered 方法(对象数组)。这样的 position dependant 存储可能是非常错误的...尝试像

{"persons":[{"name":"John","age":"31"},{"name":"Peter","age":"40"}]}