在sql server中将行/表记录转换为json文档

Posted

技术标签:

【中文标题】在sql server中将行/表记录转换为json文档【英文标题】:convert rows/table records to json document in sql server 【发布时间】:2019-06-22 07:38:08 【问题描述】:

以下是作为输入的样本数据

if object_id('tempdb.dbo.#store_data') is not null
drop table #store_data

create table #store_data ([key] nvarchar(max),[value] nvarchar(max),storeid varchar(100)
)

INSERT INTO #store_data VALUES ('sid','1','1')
INSERT INTO #store_data VALUES ('bid','3','1');
INSERT INTO #store_data VALUES ('time','2019-01-01','1');
INSERT INTO #store_data VALUES ('que','apple','1');
INSERT INTO #store_data VALUES ('sid','2','2');
INSERT INTO #store_data VALUES ('bid','5','2');
INSERT INTO #store_data VALUES ('hrs','6','2');
INSERT INTO #store_data VALUES ('dat','pine','2');

select * from #store_data

以下是需要的结果

[
"sid"="1",
"bid"="3",
"time"="2019-01-01"
"que"="apple",
"sid"="2",
"bid"="5",
"hrs"="6",
"dat"="pine"
]

以下是我尝试过的查询

select [key],[value] from #store_data for json path

没有达到预期的效果。

【问题讨论】:

您应该知道,没有隐式排序顺序! 如果没有最外层的ORDER BY,这可以工作数百次,通过所有内部测试,但会返回生产中的垃圾。如果bid=3 出现在第一个或第二个 JSON 对象中,那就不是随机的了。 我已经更新了我的答案@Shnugo...由 PSK 给出...我使用循环来获取结果集...但我觉得还有另一种方法可以按相同顺序检索跨度> 是否循环:SQL-Server 的排序方式与您插入数据的方式不同。任何没有最外层ORDER BYSELECT 都可以以任何随机排序顺序返回。如果要保持排序顺序,最简单的方法是添加IDENTITY 列。 【参考方案1】:

请注意,你不能直接查询,你必须先PIVOTstoreid

您可以尝试如下查询。

select sid, bid, time,que, hrs,dat 
from #store_data src
pivot
(
  MAX([value])
  for [key] in (sid, bid, time,que, hrs,dat)
) piv
for json auto

完整示例

 if object_id('tempdb.dbo.#store_data') is not null
 drop table #store_data

create table #store_data ([key] nvarchar(max),[value] nvarchar(max),storeid varchar(100))

INSERT INTO #store_data VALUES ('sid','1','1')
INSERT INTO #store_data VALUES ('bid','3','1');
INSERT INTO #store_data VALUES ('time','2019-01-01','1');
INSERT INTO #store_data VALUES ('que','apple','1');
INSERT INTO #store_data VALUES ('sid','2','2');
INSERT INTO #store_data VALUES ('bid','5','2');
INSERT INTO #store_data VALUES ('hrs','6','2');
INSERT INTO #store_data VALUES ('dat','pine','2');

select sid, bid, time,que, hrs,dat 
from #store_data src
pivot
(
  MAX([value])
  for [key] in (sid, bid, time,que, hrs,dat)
) piv
for json auto

输出:

[
  
    "sid": "1",
    "bid": "3",
    "time": "2019-01-01",
    "que": "apple"
  ,
  
    "sid": "2",
    "bid": "5",
    "hrs": "6",
    "dat": "pine"
  
]

在线演示:

Here

编辑:

PIVOT 自动在stroeid ASC 上订购,无需指定任何顺序。如果您想将其更改为不同的顺序,比如说DESC stroeid,在这种情况下,您可以按以下方式更改查询。

select sid, bid, time,que, hrs,dat 
from #store_data src
pivot
(
  MAX([value])
  for [key] in (sid, bid, time,que, hrs,dat)
) piv
order by storeid desc
for json auto

【讨论】:

嗨,虽然这可能是正确的方法,但我们不能厌倦指出这一事实,即 没有隐式排序顺序! 没有最外层的ORDER BY this可以工作数百次,通过所有内部测试,但会在生产中返回垃圾。如果bid=3 出现在第一个或第二个 JSON 对象中,那就不是随机的了。 嗨@Shnugo,我不确定我是否明白这一点。你的评论超出了我的认知。您能否再解释一下或一些可以重现场景的示例数据 好吧,我有点太快了,因为我没有第一眼看到storeid,它包含在SELECT *中。连同这些信息,对象将获得正确的值(作为组)。如果没有这个 storeid 作为最终 JSON 的一部分,它仍然成立,您无法保证哪个 JSON 对象将首先出现,哪个将出现在第二个。但这并不是真的反对你的方法(我这边+1) 我很高兴你已经确定了“显示顺序”@Shnugo .....我请求 PSK 和 Shnugo 在查询中没有使用 while 循环来显示相同​​的结果订购。 @Smart003,我已经编辑了答案,你可以看看。【参考方案2】:

试试这个:

drop table if exists #store_data;

create table #store_data ([key] nvarchar(max),[value] nvarchar(max),storeid varchar(100)
)

INSERT INTO #store_data VALUES ('sid','1','1')
INSERT INTO #store_data VALUES ('bid','3','1');
INSERT INTO #store_data VALUES ('time','2019-01-01','1');
INSERT INTO #store_data VALUES ('que','apple','1');
INSERT INTO #store_data VALUES ('sid','2','2');
INSERT INTO #store_data VALUES ('bid','5','2');
INSERT INTO #store_data VALUES ('hrs','6','2');
INSERT INTO #store_data VALUES ('dat','pine','2');

DECLARE @DynamicTSQLStatement NVARCHAR(MAX)
       ,@ColumnNames NVARCHAR(MAX);

SELECT @ColumnNames = STUFF
(
    (
        SELECT DISTINCT ',[' + [key] + ']'
        FROM #store_data
        FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)')
   ,1
   ,1
   ,''
);

SET @DynamicTSQLStatement = N'
select ' + @ColumnNames + '
from #store_data
PIVOT 
(
    MAX([value]) FOR [key] IN (' + @ColumnNames + ')
) PVT
FOR JSON PATH;
';


EXEC sp_executesql @DynamicTSQLStatement;

更改为 SELECT * 以便在 JSON 对象中也获得 storeid。此外,在 SQL Server 2017 中,您可以使用 STRING_AGG 连接键。

【讨论】:

查询标记为SQL Server 2017 是的,这就是为什么我说他可以使用STRING_AGG 为什么要发布 XML 连接技术呢?它隐藏了 actual 解决方案,即在将数据转换为 JSON 之前对数据进行 PIVOT 您可能会在关于不存在的隐式排序顺序的问题下方阅读我的评论.. @Shnugo 是的,你是对的。这就是为什么我指出我们可以使用SELECT * 来获取每个对象中的storeid。放在那里似乎很正常,因为它是用来对数据进行分组的。

以上是关于在sql server中将行/表记录转换为json文档的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SQL Server 或 C# 代码中将行转换为列

sql server 中将由逗号“,”分割的一个字符串,转换为一个表,并应用与 in 条件

在 SQL Server 中将行值转换为列名

在 SQL Server 中将行转换为具有特定条件的列

如何在 SQL Server 中将拆分函数转换为内联表值 udf?

如何在 SQL Server 中将纪元时间与 24 小时前进行比较?