Вывести json в словаре (список с индексами строк) с сервера SQL - PullRequest
0 голосов
/ 03 февраля 2020

У меня есть этот набор результатов на 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 server 2016+ имеет много возможностей. Но я хочу, чтобы традиционный индексированный строкой список («словарь») индексировался по идентификатору, например:

Цель

{
  "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, кажутся поверхностно значимыми, но насколько Я могу только сказать, выполняет ли прославленная конкатенация строк захват всего объекта во внешнем root узле.

Как можно сделать вышеупомянутую нотацию с использованием нативных (передовых) SQL серверных json функций?

Ответы [ 3 ]

1 голос
/ 03 февраля 2020

Вопрос помечен 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;
1 голос
/ 03 февраля 2020

Я не думаю, что вы можете сгенерировать JSON вывод с именами ключей переменных, используя FOR JSON AUTO или FOR JSON PATH, но если вы можете обновить до SQL Server 2017, следующий подход, который использует только JSON встроенная поддержка, возможен вариант:

Таблица:

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}}

Примечания:

Использование переменной или выражения вместо значения для параметра path в JSON_MODIFY() доступно в SQL Server 2017+. JSON_QUERY() используется для предотвращения экранирования специальных символов.

1 голос
/ 03 февраля 2020

К сожалению, вам нужен результат 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;

Здесь это db <> скрипка.

Однако это не так просто обобщить. Для общего решения вам может потребоваться выполнить строковые манипуляции.

...