Sql server 带有两个数组的对象上的OPENJSON

Sql server 带有两个数组的对象上的OPENJSON,sql-server,tsql,Sql Server,Tsql,我在一列中有以下json: { "fields":[ { "field":"modelName", "value":"abc123" }, { "field":"displayName", "value":"ABC 123" }, { "field":"order", "value":5 } ], "

我在一列中有以下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

但它给了我以下输出:

正如你所看到的,一切都是重复的。有可能得到我想要的输出吗


谢谢

您需要进行两次单独的解析。这使用了一个
完全外部联接
和一个(公认的)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

您将需要进行两次单独的解析。这使用了一个
完全外部联接
和一个(公认的)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

这只是另一种可能的方法(感谢@Larnu提供的测试数据)。当然,您需要分别解析
字段
变量
部分,但您可以将
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

这只是另一种可能的方法(感谢@Larnu提供的测试数据)。当然,您需要分别解析
字段
变量
部分,但您可以将
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

太好了,没想到会这么快得到答复,谢谢!但是有一个问题,如果我想过滤P.Id,那么
where
子句会去哪里?我试着将它放在单独的语法分析中,但无法获得正确的语法。我不确定是否把它放在最后一个select语句中。“SQL是否足够聪明,可以只抓取我想要的,或者它会抓取每个解析器中的所有内容,然后过滤掉它呢?我会,但它会在CTE中,”阿德林格说。语法应该是
,其中P.ID=1
<代码>其中是SQL的基础之一,因此如果您不熟悉它,我建议您阅读一下。非常好,没想到会有这么快的答案,谢谢!但是有一个问题,如果我想过滤P.Id,那么
where
子句会去哪里?我试着将它放在单独的语法分析中,但无法获得正确的语法。我不确定是否把它放在最后一个select语句中。“SQL是否足够聪明,可以只抓取我想要的,或者它会抓取每个解析器中的所有内容,然后过滤掉它呢?我会,但它会在CTE中,”阿德林格说。语法应该是
,其中P.ID=1
<代码>其中是SQL的基础之一,因此如果您不熟悉它,我建议您阅读一下。