【问题标题】:How can I use FOR JSON to build JSON in this format?如何使用 FOR JSON 构建这种格式的 JSON?
【发布时间】:2020-01-22 10:56:39
【问题描述】:

我想使用 FOR JSON 为 HTTP Post 调用构建数据负载。我的源表可以用这个 sn-p 重新创建:

drop table if exists #jsonData;
drop table if exists #jsonColumns;

select
    'carat' [column] 
into #jsonColumns
union
select 'cut' union
select 'color' union
select 'clarity' union
select 'depth' union
select 'table' union
select 'x' union
select 'y' union
select 'z'

select
    0.23 carat
    ,'Ideal' cut
    ,'E' color
    ,'SI2' clarity
    ,61.5 depth
    ,55.0 [table]
    ,3.95 x
    ,3.98 y
    ,2.43 z
into #jsonData
union
select 0.21,'Premium','E','SI1',59.8,61.0,3.89,3.84,2.31 union
select 0.29,'Premium','I','VS2',62.4,58.0,4.2,4.23,2.63 union
select 0.31,'Good','J','SI2',63.3,58.0,4.34,4.35,2.75
;

数据需要格式化如下:

{
    "columns":["carat","cut","color","clarity","depth","table","x","y","z"],
    "data":[
        [0.23,"Ideal","E","SI2",61.5,55.0,3.95,3.98,2.43],
        [0.21,"Premium","E","SI1",59.8,61.0,3.89,3.84,2.31],
        [0.23,"Good","E","VS1",56.9,65.0,4.05,4.07,2.31],
        [0.29,"Premium","I","VS2",62.4,58.0,4.2,4.23,2.63],
        [0.31,"Good","J","SI2",63.3,58.0,4.34,4.35,2.75]
    ]
}

到目前为止,我的尝试如下:

select
    (select * from #jsonColumns for json path) as [columns],
    (select * from #jsonData for json path) as [data]
for json path, without_array_wrapper

但是,这会返回 objects 数组而不是 values,如下所示:

{
    "columns":[
        {"column":"carat"},
        {"column":"clarity"},
        {"column":"color"},
        {"column":"cut"},
        {"column":"depth"},
        {"column":"table"},
        {"column":"x"},
        {"column":"y"},
        {"column":"z"}
    ]...
}

如何将数组限制为仅显示值?

【问题讨论】:

  • 请向我们展示您的尝试,就好像您快到了一样,我们更容易纠正它们。
  • 然而,从预期的结果来看,它看起来不像是格式特别好的 JSON 数据。
  • @Larnu 已更新;我设法解决了这两个问题之一。我不评论格式的有效性;它是由预期接收者的限制所规定的。

标签: json sql-server sql-server-2016 for-json


【解决方案1】:

老实说,使用字符串聚合而不是使用 JSON 功能似乎会更容易。

由于您使用的是 SQL Server 2016,因此您无权访问 STRING_AGG 或 CONCAT_WS,因此代码较长。您必须改用FOR XML PATH 和STUFF 并手动插入所有分隔符(为什么CONCAT 表达式中有这么多',')。结果如下:

DECLARE @CRLF nchar(2) = NCHAR(13) + NCHAR(10);

SELECT N'{' + @CRLF +
       N'    "columns":[' + STUFF((SELECT ',' + QUOTENAME(c.[name],'"')
                                   FROM tempdb.sys.columns c
                                        JOIN tempdb.sys.tables t ON c.object_id = t.object_id
                                   WHERE t.[name] LIKE N'#jsonData%' --Like isn't needed if not a temporary table. Use the literal name.
                                   ORDER BY c.column_id ASC
                                   FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,1,N'') + N'],' + @CRLF +
       N'    "data":[' + @CRLF +
       STUFF((SELECT N',' + @CRLF +
                     N'       ' + CONCAT('[',JD.carat,',',QUOTENAME(JD.cut,'"'),',',QUOTENAME(JD.color,'"'),',',QUOTENAME(JD.clarity,'"'),',',JD.depth,',',JD.[table],',',JD.x,',',JD.y,',',JD.z,']')
              FROM #jsonData JD
              ORDER BY JD.carat ASC
              FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,3,N'') + @CRLF +
      N'    ]' + @CRLF +
      N'}';

DB<>Fiddle

【讨论】:

  • 谢谢,让我试试这个。您错过了一个我无法插入的逗号,因为编辑最少需要 6 个字符; FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,1,N'') + N']' + @CRLF + 应该是 FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,1,N'') + N'], ' + @CRLF +
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-04
  • 1970-01-01
  • 2021-07-01
  • 1970-01-01
  • 2023-03-05
相关资源
最近更新 更多