SQL JSON_值/JSON_查询来自数组并转置到行
我想从Microsoft SQL Server数据库中JSON字符串内的数组中提取信息 如果我有这样一个JSON对象:SQL JSON_值/JSON_查询来自数组并转置到行,sql,arrays,json,sql-server,Sql,Arrays,Json,Sql Server,我想从Microsoft SQL Server数据库中JSON字符串内的数组中提取信息 如果我有这样一个JSON对象: CREATE TABLE myTable([Id] int, [JsonInfo] varchar(max)); INSERT INTO myTable ([Id], [JsonInfo]) VALUES (1, '{ "$id": "1", "Id": "3276617
CREATE TABLE myTable([Id] int, [JsonInfo] varchar(max));
INSERT INTO myTable ([Id], [JsonInfo])
VALUES (1,
'{
"$id": "1",
"Id": "32766177-18c7-4c2d-bbb5-02588a73ff72",
"Metadata": [
{
"Identifier": "Identifier1",
"Value": "aaa"
},
{
"Identifier": "Identifier2",
"Value": "bbb"
},
{
"Identifier": "Identifier3",
"Value": "ccc"
},
],
}'
);
我发现访问整个阵列的唯一方法是:
SELECT Id, value AS Metadata
FROM myTable t
CROSS APPLY OPENJSON( JSON_QUERY(t.JsonInfo, '$.Metadata'))
要访问阵列中的信息,我执行了以下操作:
SELECT
JSON_VALUE(Metadata, '$.Identifier') AS Identifier,
JSON_VALUE(Metadata, '$.Value') AS Value
FROM
(SELECT Id, value AS Metadata
FROM myTable t
CROSS APPLY OPENJSON( JSON_QUERY(t.JsonInfo, '$.Metadata'))
);
-- Declare a variable to hold the dynamic SQL statement.
DECLARE @sql VARCHAR(MAX) = ''; -- must be initialized as an empty string.
-- Using the SQL hack to append continuous rows to a variable, we can build a list
-- of column names and their values from your JSON.
SELECT
@sql = @sql + ', NULLIF ( ''' + md.[Value] + ''', '''' ) AS [' + md.Identifier + ']'
FROM @myTable AS mt
OUTER APPLY (
SELECT
Identifier, [Value]
FROM OPENJSON ( JsonInfo, '$.Metadata' ) WITH (
Identifier VARCHAR(50) '$.Identifier',
[Value] VARCHAR(50) '$.Value'
) AS ids
) AS md
WHERE mt.Id = 1; -- <= note the record restriction.
-- Complete the dynamic SQL statement by adding SELECT and trimming
-- off the prefixed ", " from the column/value list by using STUFF.
SET @sql = 'SELECT ' + STUFF ( @sql, 1, 2, '' ) + ';';
-- Execute the dynamic statement.
EXEC ( @sql );
我的结果是:
Identifier | Value
------------+--------
Identifier1 | aaa
Identifier2 | bbb
Identifier3 | ccc
结果我应该是:
Identifier1 | Identifier2 | Identifier3
------------+-------------+------------
aaa | bbb | ccc
具有不匹配记录的结果:
Identifier1 | Identifier2 | Identifier3 |Identifier4
------------+-------------+-------------+-----------
aaa | bbb | ccc | NULL
aaa | bbb | NULL | ddd
我知道我可以用PIVOT转换它,但是对于这个场景来说它似乎太复杂了
关于如何轻松实现这一点,有什么建议吗?注意:您提供的JSON无效。为了我的例子,我不得不修改它。如果JSON示例是生产数据的外观,那么您还有其他问题需要解决 最简单的方法是对数据进行透视,如下所示:
DECLARE @myTable TABLE ( [Id] INT, [JsonInfo] VARCHAR(MAX) );
INSERT INTO @myTable ( [Id], [JsonInfo] )
VALUES (1,
'{
"$id": "1",
"Id": "32766177-18c7-4c2d-bbb5-02588a73ff72",
"Metadata": [
{
"Identifier": "Identifier1",
"Value": "aaa"
},
{
"Identifier": "Identifier2",
"Value": "bbb"
},
{
"Identifier": "Identifier3",
"Value": "ccc"
},
{
"Identifier": "Identifier4",
"Value": ""
}
]
}'
);
SELECT
Id, md.*
FROM @myTable AS mt
OUTER APPLY (
SELECT * FROM (
SELECT Identifier, [Value] FROM OPENJSON ( JsonInfo, '$.Metadata' ) WITH (
Identifier VARCHAR(50) '$.Identifier',
[Value] VARCHAR(50) '$.Value'
)
) AS ids
PIVOT (
MAX ( [Value] ) FOR Identifier IN ( [Identifier1], [Identifier2], [Identifier3], [Identifier4] )
) AS pvt
) AS md;
返回
+----+-------------+-------------+-------------+-------------+
| Id | Identifier1 | Identifier2 | Identifier3 | Identifier4 |
+----+-------------+-------------+-------------+-------------+
| 1 | aaa | bbb | ccc | |
+----+-------------+-------------+-------------+-------------+
+-------------+-------------+-------------+-------------+
| Identifier1 | Identifier2 | Identifier3 | Identifier4 |
+-------------+-------------+-------------+-------------+
| aaa | bbb | ccc | NULL |
+-------------+-------------+-------------+-------------+
这种方法只有在您知道每个标识符的预期值和行数的情况下才有效,我怀疑您已经提到过PIVOT
。因此,您将被迫使用动态SQL方法
我不完全理解您的需求,因为我不确定您的示例中不匹配的数据来自JSON的何处,但是,继续上面的相同设置,您可以尝试以下操作:
SELECT
JSON_VALUE(Metadata, '$.Identifier') AS Identifier,
JSON_VALUE(Metadata, '$.Value') AS Value
FROM
(SELECT Id, value AS Metadata
FROM myTable t
CROSS APPLY OPENJSON( JSON_QUERY(t.JsonInfo, '$.Metadata'))
);
-- Declare a variable to hold the dynamic SQL statement.
DECLARE @sql VARCHAR(MAX) = ''; -- must be initialized as an empty string.
-- Using the SQL hack to append continuous rows to a variable, we can build a list
-- of column names and their values from your JSON.
SELECT
@sql = @sql + ', NULLIF ( ''' + md.[Value] + ''', '''' ) AS [' + md.Identifier + ']'
FROM @myTable AS mt
OUTER APPLY (
SELECT
Identifier, [Value]
FROM OPENJSON ( JsonInfo, '$.Metadata' ) WITH (
Identifier VARCHAR(50) '$.Identifier',
[Value] VARCHAR(50) '$.Value'
) AS ids
) AS md
WHERE mt.Id = 1; -- <= note the record restriction.
-- Complete the dynamic SQL statement by adding SELECT and trimming
-- off the prefixed ", " from the column/value list by using STUFF.
SET @sql = 'SELECT ' + STUFF ( @sql, 1, 2, '' ) + ';';
-- Execute the dynamic statement.
EXEC ( @sql );
如果要打印已完成的@sql变量,您将看到:
SELECT NULLIF ( 'aaa', '' ) AS [Identifier1], NULLIF ( 'bbb', '' ) AS [Identifier2], NULLIF ( 'ccc', '' ) AS [Identifier3], NULLIF ( '', '' ) AS [Identifier4];
希望这能帮助您上路。您的语句有语法错误(JSON\u query
,JSON\u值(元数据,$.Identifier)
),JSON无效。$.Metadata
是否始终具有固定的项目计数?$.Metadata
具有动态范围如果myTable
表中的第二行具有$.Metadata
JSON数组,包含五个项目,那么这两行的预期结果是什么?我在问题中添加了一个示例。如果JSON值不存在,它应该返回空值。感谢您的详细解释!我设法用动态SQL解决了这个问题。尽管我希望在JSON处理中有一个解决方案。我仍然需要测试它在处理更大数据时的效果。最终的结果必须在小型工业PC上运行,可以有数千个对象,总的来说可能有50个不同的元标记。但我相信这仍然比事后用C代码处理要好。不客气。我理解使用动态SQL的挫折感,因为这几乎是我最后的选择。也许有更好的方法可以做到这一点,但通常情况下,当您旋转未知数据时,没有很多其他选项。希望它能在你的小型电脑上正常工作。