OPENJSON на объекте с двумя массивами - PullRequest
1 голос
/ 25 октября 2019

У меня есть следующий json в столбце:

{
   "fields":[
      {
         "field":"modelName",
         "value":"abc123"
      },
      {
         "field":"displayName",
         "value":"ABC 123"
      },
      {
         "field":"order",
         "value":5
      }
   ],
   "variables":[
      {
         "varId":4,
         "oldValue":100,
         "newValue":"150"
      },
      {
         "varId":5,
         "oldValue":"abc",
         "newValue":"def"
      }
   ]
}

И я хотел бы вытащить эту информацию примерно так:

Id  Field        Value    VarId    oldValue    newValue    
2   modelName    abc123   null     null        null
2   displayName  ABC 123  null     null        null
2   order        5        null     null        null
2   null         null     4        100         150
2   null         null     5        abc         def

Таким образом, я могу простоитерируйте по набору результатов и просто проверите ноль, чтобы увидеть, какой это тип.

В настоящее время у меня есть следующее утверждение:

select Id, Fields.Field, Fields.Value, Variables.VarId, Variables.OldValue, Variables.NewValue from  Product
cross apply openjson( data, '$.fields') with (Field varchar(50) '$.field', Value varchar(50) '$.value') AS Fields
cross apply openjson( data, '$.variables') with (VarId int '$.varId', OldValue varchar(50) '$.oldValue', NewValue varchar(50) '$.newValue') AS Variables

Но это дает мне следующий вывод:

enter image description here

Как видите, все продублировано. Возможно ли получить желаемый результат?

Спасибо

Ответы [ 2 ]

2 голосов
/ 25 октября 2019

Вам нужно будет сделать это как 2 отдельных разбора. При этом используется FULL OUTER JOIN с (по общему признанию) dumb ON предложением. Вы также можете использовать UNION ALL и NULL значения в наборе, которые не имеют столбцов:

CREATE TABLE dbo.Product (ID int,
                          [data] nvarchar(MAX));

DECLARE @JSON nvarchar(MAX) = N'{
   "fields":[
      {
         "field":"modelName",
         "value":"abc123"
      },
      {
         "field":"displayName",
         "value":"ABC 123"
      },
      {
         "field":"order",
         "value":5
      }
   ],
   "variables":[
      {
         "varId":4,
         "oldValue":100,
         "newValue":"150"
      },
      {
         "varId":5,
         "oldValue":"abc",
         "newValue":"def"
      }
   ]
}';

INSERT INTO dbo.Product (ID,
                         [data])
VALUES(2,@JSON);
GO

WITH Fields AS(
    SELECT P.Id,
           F.Field,
           F.Value,
    FROM Product P
         CROSS APPLY OPENJSON(data, '$.fields')
                     WITH (Field varchar(50) '$.field',
                           [Value] varchar(50) '$.value') F),
Variables AS(
    SELECT P.Id,
           V.VarId,
           V.OldValue,
           V.NewValue
    FROM Product P
    CROSS APPLY OPENJSON(data, '$.variables')
                WITH (VarId int '$.varId',
                      OldValue varchar(50) '$.oldValue',
                      NewValue varchar(50) '$.newValue') V)
SELECT ISNULL(F.ID,V.ID) AS ID,
       F.Field,
       F.[Value],
       V.VarId,
       V.OldValue,
       V.NewValue
FROM Fields F
     FULL OUTER JOIN Variables V ON 1 = 2; --Dumb ON clause is Dumb
1 голос
/ 25 октября 2019

Это просто еще один возможный подход (спасибо, @Larnu, за данные теста). Конечно, вам нужно разобрать fields и variables детали по отдельности, но вы можете использовать OPENJSON() с одной явной схемой (предложение WITH):

Таблица:

CREATE TABLE Product (
   ID int,
   [data] nvarchar(MAX)
);
DECLARE @json nvarchar(MAX) = N'{
   "fields":[
      {
         "field":"modelName",
         "value":"abc123"
      },
      {
         "field":"displayName",
         "value":"ABC 123"
      },
      {
         "field":"order",
         "value":5
      }
   ],
   "variables":[
      {
         "varId":4,
         "oldValue":100,
         "newValue":"150"
      },
      {
         "varId":5,
         "oldValue":"abc",
         "newValue":"def"
      }
   ]
}';

INSERT INTO Product (ID, [data])
VALUES
   (1, @json),
   (2, @json),
   (3, @json)

Заявление:

SELECT p.ID, j.*
FROM Product p
CROSS APPLY (
   SELECT *
   FROM OPENJSON (p.data, '$.fields') WITH (
      field varchar(100) '$.field',
      value varchar(100) '$.value',
      varId int '$.varId',
      oldValue varchar(100) '$.oldValue',
      newValue varchar(100) '$.newValue'
   )
   UNION ALL 
   SELECT *
   FROM OPENJSON (p.data, '$.variables') WITH (
      field varchar(100) '$.field',
      value varchar(100) '$.value',
      varId int '$.varId',
      oldValue varchar(100) '$.oldValue',
      newValue varchar(100) '$.newValue'
   )
) j
-- Additional WHERE clause
--WHERE p.ID = 2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...