从 SQL 服务器以字典(字符串索引列表)表示法输出 json

Output json in dictionary (string-indexed list) notation from SQL Server

我在 SQL 服务器中设置了这个结果:

ID   CUSTOMER   PRODUCT   DATE       COUNT
A1   Walmart    Widget    1/1/2020   5
B2   Amazon     Thingy    1/2/2020   10
C3   Target     Gadget    2/1/2020   7

我想将它输出为 json,SQL 服务器 2016+ 有足够的能力来做。但我想要一个由 id 索引的传统字符串索引列表 ('dictionary'),如下所示:

目标

{
  "A1": {"Customer":"Walmart", "Product":"Widget", "Date":"1/1/2020", "Count":5 },
  "B2": {"Customer":"Amazon",  "Product":"Thingy", "Date":"1/2/2020", "Count":10},
  "C3": {"Customer":"Target",  "Product":"Gadget", "Date":"2/1/2020", "Count":7 }
}

但是,典型的 select * from table for json path 输出为未索引的对象数组:

当前状态

[
  {"Id":"A1", "Customer":"Walmart", "Product":"Widget", "Date":"1/1/2020", "Count":5 },
  {"Id":"B2", "Customer":"Amazon",  "Product":"Thingy", "Date":"1/2/2020", "Count":10},
  {"Id":"C3", "Customer":"Target",  "Product":"Gadget", "Date":"2/1/2020", "Count":7 }
]

其他 for json 修饰符,如 root 表面上看起来很相关,但据我所知,只是在外部根节点中捕获整个对象的美化字符串连接。

如何使用本机(性能)SQL 服务器 json 函数完成上述表示法?

不幸的是,您想要一个 JSON 结果,该结果具有从数据派生的多个值(A1、B2 和 C3)。这意味着您需要将数据聚合到一行中。通常,for json path 会想要创建一个值数组,每行一个值。

所以,这应该可以满足您的要求:

select json_query(max(case when id = 'A1' then j.p end)) as A1,
       json_query(max(case when id = 'B2' then j.p end)) as B2,
       json_query(max(case when id = 'B3' then j.p end)) as B3
from t cross apply
     (select t.customer, t.product, t.date, t.count
      for json path
     ) j(p)
for json path;

Here 是一个 db<>fiddle.

然而,它不容易推广。对于一般解决方案,您可能需要进行字符串操作。

问题被标记为 sql2016,string_agg() 将不起作用...(使用 xpath 或自定义聚合进行聚合)

declare @t table
(
Id varchar(10),
CUSTOMER varchar(50),
PRODUCT varchar(50),
[DATE] date,
[COUNT] int
);

insert into @t(Id, CUSTOMER, PRODUCT, [DATE], [COUNT])
values
('A1','Walmart','Widget','20200101', 5),
('B2','Amazon','Thingy','20200201', 10),
('C3','Target','Gadget','20200102', 7);


select concat('{', STRING_AGG(thejson, ','), '}')
from 
(
select concat('"', STRING_ESCAPE(Id, 'json'), '":', (select CUSTOMER, PRODUCT, DATE, COUNT for json path, without_array_wrapper )) as thejson
from @t
) as src;

我认为您无法使用 FOR JSON AUTOFOR JSON PATH 生成具有可变键名的 JSON 输出,但如果您可以升级到 SQL Server 2017 ,以下方法仅使用 JSON 内置支持,是一种可能的选择:

Table:

CREATE TABLE Data (
   Id varchar(2), 
   Customer varchar(50),
   Product varchar(50),   
   [Date] date,       
   [Count] int
)
INSERT INTO Data 
   (Id, Customer, Product, [Date], [Count])
VALUES   
   ('A1', 'Walmart', 'Widget', '20200101', 5),
   ('B2', 'Amazon',  'Thingy', '20200102', 10),
   ('C3', 'Target',  'Gadget', '20200201', 7)

声明:

DECLARE @json nvarchar(max) = N'{}'   
SELECT @json = JSON_MODIFY(
   @json, 
   CONCAT(N'$."', ID, N'"'), 
   JSON_QUERY((SELECT Customer, Product, [Date], [Count] FOR JSON PATH, WITHOUT_ARRAY_WRAPPER))
)
FROM Data

SELECT @json

结果:

{"A1":{"Customer":"Walmart","Product":"Widget","Date":"2020-01-01","Count":5},"B2":{"Customer":"Amazon","Product":"Thingy","Date":"2020-01-02","Count":10},"C3":{"Customer":"Target","Product":"Gadget","Date":"2020-02-01","Count":7}}

备注:

JSON_MODIFY() 中的 path 参数使用变量或表达式代替值在 SQL Server 2017+ 中可用。 JSON_QUERY()用于防止特殊字符转义。