arrays - T-SQL 解析包含动态值数组的 JSON

标签 arrays json t-sql

在 T-SQL 中,解析 JSON 并以动态方式处理数组似乎很清楚,需要使用 OPENJSON 表值函数来处理不知道可用索引的事实。如果这个数组是一个简单的值数组:

SELECT *
FROM OPENJSON(N'["element1","element2","element3"]')

正如人们所期望的那样,它每行呈现一个元素;非常适合计算行数和迭代值。但是,我需要反向执行此操作并构建一个值数组。为了测试我认为这样的东西可能有效:

SELECT RTRIM([value])
FROM OPENJSON(N'["element1","element2","element3"]')
ORDER BY [key] FOR JSON PATH

但我收到错误:

Msg 13605, Level 16, State 1, Line 8 Column expressions and data sources without names or aliases cannot be formatted as JSON text using FOR JSON clause. Add alias to the unnamed column or table.

我尝试过各种形式的 OPENJSON 函数和 JSON_QUERY 函数,但没有成功。最终我确实得出了这个“解决方案”:

SELECT REPLACE(REPLACE(REPLACE(CATEND,'},{"V":',','),'[{"V":','['),'}]',']')
FROM (
    SELECT (
        SELECT [value] AS V
        FROM OPENJSON(N'["element1","element2","element3"]')
        ORDER BY [key] FOR JSON PATH
    ) AS CATEND
) T

但这对我来说不太合适。我使用 JSON 库函数的重点和目的是避免文本解析,并且必须包含昂贵的 REPLACE 函数,感觉好像没有必要。我错过了什么吗?!

最佳答案

遗憾的是,开发人员忘记添加诸如 AS ARRAY 提示之类的内容。

OPENJSON() 可以读取裸数组,其中 [key] 是元素的位置,[value] 是项目,但我们无法使用 JSON 功能创建这样的数组:

有一些解决方法:

--创建一个模型来模拟您的问题:

DECLARE @tbl1 TABLE(ID INT IDENTITY,SomeValue VARCHAR(100));
INSERT INTO @tbl1 VALUES('Row 1'),('Row 2');

DECLARE @tbl2 TABLE(ID1 INT,SomeDetail VARCHAR(100));
INSERT INTO @tbl2 VALUES(1,'Det 1.1'),(1,'Det 1.2')
                       ,(2,'Det 2.1'),(2,'Det 2.2.'),(2,'Det 2.3');

--使用AUTO模式将检测JOIN并创建对象数组。
--这很接近,但你不会得到未命名的数组:

SELECT *
FROM @tbl1 t1
INNER JOIN @tbl2 t2 ON t1.ID=t2.ID1
FOR JSON AUTO;

/*
    {
        "ID": 1,
        "SomeValue": "Row 1",
        "t2": [
            {
                "ID1": 1,
                "SomeDetail": "Det 1.1"
            },
            {
                "ID1": 1,
                "SomeDetail": "Det 1.2"
            }
        ]
    }
*/

--使用 PATH 模式将返回每个组合 - 不是您需要的

SELECT *
FROM @tbl1 t1
INNER JOIN @tbl2 t2 ON t1.ID=t2.ID1
FOR JSON PATH;

/*
    {
        "ID": 1,
        "SomeValue": "Row 1",
        "ID1": 1,
        "SomeDetail": "Det 1.1"
    }
*/

--使用相关子查询将得到与上面AUTO模式相同的结果

SELECT *
      ,(
        SELECT *
        FROM @tbl2 t2 
        WHERE t2.ID1=t1.ID --<-- correlated sub-query 
        FOR JSON PATH
       ) AS Details
FROM @tbl1 t1
FOR JSON PATH;

--因此我们可以将相关子查询与用于字符串连接的 XML 黑客一起使用:

SELECT *
      ,JSON_QUERY
      (
           CONCAT('['
          ,STUFF((
            SELECT CONCAT(',"',t2.SomeDetail,'"') 
            FROM @tbl2 t2 
            WHERE t2.ID1=t1.ID --<-- correlated sub-query 
            FOR XML PATH(''),TYPE).value('.','nvarchar(max)'),1,1,''),']')
      ) AS Details
FROM @tbl1 t1
FOR JSON PATH;

--最后这就是你想要的:

/*
    {
        "ID": 1,
        "SomeValue": "Row 1",
        "Details": [
            "Det 1.1",
            "Det 1.2"
        ]
    }
*/

如果您有 v2017+,那么您很幸运,因为您可以使用 STRING_AGG():

SELECT t1.ID
      ,JSON_QUERY(CONCAT('[',STRING_AGG(CONCAT('"',t2.SomeDetail,'"'),','),']')) AS Details
FROM @tbl1 t1
INNER JOIN @tbl2 t2 ON t1.ID=t2.ID1
GROUP BY t1.ID
FOR JSON PATH;

目前我们必须等待 future 的版本来原生地引入这个真正需要的功能......

关于arrays - T-SQL 解析包含动态值数组的 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58779825/

相关文章:

c - 数组的统计

php - PHP:根据另一个数组的值将一个数组拆分为不同大小的 block

javascript - jQuery: "Access to restricted URI denied"中的跨域 AJAX 调用结果(代码 1012)

javascript - ExtJS网格过滤器: how can I load 'list' filter options from external json?

sql-server-2008 - T-SQL 从表中删除重复项?

javascript - onClick 过滤数组并渲染数组中的剩余项目

php - php中的奇怪输出

javascript - 在 JavaScript 中有效地将数组映射到字符串

sql - 将 IF 和临时表与变量以及 BEGIN/END 语句结合使用

sql-server - SQL 错误 - 必须声明表变量 "@tablename"