#sql #json #sql-server #tsql
#sql #json #sql-сервер #tsql
Вопрос:
Я знаю, что подобные вопросы задавались несколько раз, однако мой сценарий, похоже, немного отличается.
Моя таблица базы данных выглядит следующим образом:
App ID | ID | JSONData | URL | CreatedOn
---------- ----------- ------------------- -------------- -----------------
5b5cd8 | 1 | {"F":"B", "S":"D"}| http://local | Mar 19 2018 13:04
5b5cd8 | 2 | {"F":"C", "S":"K"}| http://remote| Mar 29 2018 09:34
6b9df0 | 3 | {"T":"N", "D":"S"}| http://site | Apr 04 2018 16:12
App ID
столбец может иметь разные значения, однако структура JSONData
(* должна быть) одинаковой для одного и того же App ID
.
Могу ли я в любом случае разделить JSONData
данные и получить такой результат?
App ID | ID | F | S | URL | CreatedOn
---------- ----------- ----- ----- -------------- -------------------------
5b5cd8 | 1 | B | D | http://local | Mar 19 2018 13:04
5b5cd8 | 2 | C | K | http://remote| Mar 29 2018 09:34
Для следующего App ID
это выглядит следующим образом
App ID | ID | T | D | URL | CreatedOn
---------- ----------- ----- ----- -------------- -------------------------
6b9df0 | 3 | N | S | http://site | Apr 04 2018 16:12
Примечание: Данные в JSONData
поле будут в основном одноуровневыми, т. е. все данные будут строковыми и никаких дополнительных объектов.
Решение, которое я нашел в большинстве случаев, подобных этому, заключалось либо в использовании имен статических ключей JSON для разделения, либо в создании временной таблицы, которая вызовет проблемы с производительностью.
Комментарии:
1. В результате запроса не может быть произвольных столбцов. Вы не можете иметь столбец с именем T в одной строке и переименовывать его в F в другой.
2. @PanagiotisKanavos, запросы будут разными и будут зависеть от
App ID
столбца как части предложения where. Таким образом, мы можем предположить, что у нас не будет случая, когда нам понадобится иметь столбецF
иT
, т.е.App ID
s6b9df0
amp;5b5cd8
, как часть того же запроса select.
Ответ №1:
Вам уже говорили, что имена столбцов результирующего набора должны быть известны заранее.
Единственным обходным путем был динамический SQL (создание инструкции в виде строки и EXEC()
получение ее результата). Но у этого есть некоторые серьезные недостатки (и некоторые преимущества)…
Вы могли бы использовать что-то в этом роде (требуется SQL-Server 2016 ):
Макетный стол
DECLARE @tbl TABLE(AppID VARCHAR(100),ID INT,JSONData NVARCHAR(MAX));
INSERT INTO @tbl VALUES
('5b5cd8',1,N'{"F":"B", "S":"D"}')
,('5b5cd8',2,N'{"F":"C", "S":"K"}')
,('6b9df0',3,N'{"T":"N", "D":"S"}');
—Этот запрос извлекает значения с помощью JSON_VALUE
—Вам нужно будет создать одну инструкцию для каждого возможного списка столбцов
— Применить WHERE
для фильтрации соответствующих строк
SELECT t.AppID
,t.ID
,JSON_VALUE(t.JSONData,'$.F') AS F
,JSON_VALUE(t.JSONData,'$.S') AS S
FROM @tbl t
WHERE t.AppID='5b5cd8'
—Вы могли бы включить все возможные столбцы
—Это работает без фильтра, но вернет много нулей
SELECT t.AppID
,t.ID
,JSON_VALUE(t.JSONData,'$.F') AS F
,JSON_VALUE(t.JSONData,'$.S') AS S
,JSON_VALUE(t.JSONData,'$.T') AS T
,JSON_VALUE(t.JSONData,'$.D') AS D
FROM @tbl t
— Немного чище / лучше для чтения было OPENJSON()
в связи с WITH
предложением
SELECT t.AppID
,t.ID
,JsonColumns.*
FROM @tbl t
CROSS APPLY OPENJSON(t.JSONData) WITH(F CHAR(1)
,S CHAR(1)
,T CHAR(1)
,D CHAR(1)) JsonColumns
Мое предложение: создайте последний в виде VIEW или (возможно, лучше) iTVF и используйте для этого специальные инструкции, по одной для каждого типа структуры.