Как я могу использовать FOR JSON для построения JSON в этом формате? - PullRequest
0 голосов
/ 22 января 2020

Я хотел бы использовать FOR JSON для создания полезной нагрузки данных для вызова HTTP Post. Моя исходная таблица может быть воссоздана с помощью этого фрагмента:

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

Однако это возвращает массивы объектов , а не значений , например:

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

Как я могу ограничить массивы только показом значений?

1 Ответ

1 голос
/ 22 января 2020

Честно говоря, похоже, что с агрегацией строк будет проще, чем с использованием функции 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

...