【问题标题】:How to parse JSON column to a table with TSQL如何使用 TSQL 将 JSON 列解析为表
【发布时间】:2019-03-27 22:45:14
【问题描述】:

我正在尝试打开一个 JSON 字符串并让每个键成为自己的列。 JSON 列位于具有键和多态 id 的元数据表中。

我希望能够将每个键解析到自己的列中,并为每个多态 id 填充对应的值。

我可以使用 json_query 逐个解析每个键,但我看到有一个函数调用 openjson 可以解析整个字符串,但我不知道如何使用它,因为文档中的示例正在应用该函数在设定值而不是表中的列上。如果有比使用 json_query 更简单的方法来解析 JSON 字符串?

【问题讨论】:

  • 请提供基于文本的日期,而不是图片。这将大大增加收到答案的机会。

标签: json sql-server sql-server-2016


【解决方案1】:

我会尝试这种方法

SELECT t.RelatedPolimorphicId
      ,t.[Key] 
      ,A.*
FROM YourMetaDataTable t
CROSS APPLY OPENJSON(t.[Value]) 
WITH (
     BrandPresent BIT
    ,OneImage BIT
    ,UPCPresenet BIT
    ,ModelNumberPresent BIT
    ,TitlePresent BIT
    ,DescriptionPresent BIT
    ,Feature1Present BIT
) A;

OPENJSON 结合WITH 子句提供了一种漂亮、干净且类型安全的(!)方法来读取您的 JSON。我会使用BIT,因为truefalse 将被隐式翻译。

【讨论】:

  • 如果ModelNumberPresent 是一个数组,而您也想“分解”它怎么办?
  • @CutePoison 只需将另一个调用添加到openjson(A.ModelNumberPresent) B 并检查结果(将BIT 更改为NVARCHAR(MAX) AS Json 并将B.* 添加到选择列表中)。
  • 如果您愿意,可以将该答案添加到stackoverflow.com/questions/64424626/…
【解决方案2】:

您可以尝试使用OPENJSON()WITH 子句(指定列及其类型)的下一种方法。如果没有 WITH 子句,OPENJSON 将返回三列 - 每个 {key: value} 对中的 keyvaluetype

输入

CREATE TABLE #Table (
   RelatedPolimorphicId int,
   [Key] nvarchar(50),
   [Value] varchar(max)
)
INSERT INTO #Table
   (RelatedPolimorphicId, [Key], [Value])
VALUES
   (23, N'ContentStats', N'{"BrandPresent": true, "OneImage": true, "UPCPresenet": true, "ModelNumberPresent": true, "TitlePresent": true, "DescriptionPresent": true, "Feature1Present": true}')

声明

SELECT 
   t.RelatedPolimorphicId,
   j.*
FROM #Table t
CROSS APPLY (
   SELECT * 
   FROM OPENJSON(t.[Value])
   WITH (
       BrandPresent varchar(10) '$.BrandPresent',
       OneImage varchar(10) '$.OneImage',
       UPCPresenet varchar(10) '$.UPCPresenet',
       ModelNumberPresent varchar(10) '$.ModelNumberPresent',
       TitlePresent varchar(10) '$.TitlePresent',
       DescriptionPresent varchar(10) '$.TitlePresent',
       Feature1Present varchar(10) '$.Feature1Present'
   )
) j

输出

RelatedPolimorphicId    BrandPresent    OneImage    UPCPresenet ModelNumberPresent  TitlePresent    DescriptionPresent  Feature1Present
23                      true            true        true        true              true              true            true

【讨论】:

  • 这在原则上是正确的,但是很复杂(不需要子选择)。仍然是我的支持。
【解决方案3】:

请试试这个:

SELECT p.RelatedPolymorphId,p.[BrandPresent],p.[OneImage],p.[UPCPresent],p.[ModelNumberPresent],p.[TitlePresent],p.[DescriptionPresent],p.[Feature1Present]
FROM (SELECT v.RelatedPolymorphId,v.Value AS [JsonValue] FROM [YourTableName] v) a
CROSS APPLY OPENJSON(a.JsonValue) j
PIVOT(MAX(j.[value]) FOR j.[key] IN ([BrandPresent],[OneImage],[UPCPresent],[ModelNumberPresent],[TitlePresent],[DescriptionPresent],[Feature1Present])) p
;

【讨论】:

  • 不,PIVOT 在这里是错误的方法。更好地将OPENJSONWITH 子句结合使用。除了速度之外,优势在于您可以在每个派生列中放置类型。此外,可以轻松地在WITH 中设置列​​别名。我们经常需要深入研究嵌套的 JSON。如果没有WITH,这将是一团糟……请参阅我的答案以获取示例
  • 为什么是“错误的方法”?它只是在某些情况下有用。
  • 不,有一点是,该枢轴将迫使您返回所有具有相同类型的数据,由于聚合可能会出现意外结果,这是一个巨大的开销,并且不允许 Json 层次结构。
  • OPENJSON 返回 NVARCHAR - 结果和聚合总是如预期的那样。我看你是“不”字的粉丝。
  • 不,?,With 子句允许指定类型。做任何你想做的事,在我看来这是错误的方法......快乐编码
【解决方案4】:

感谢大家的回复。 @shnugo,在您使用openjson的解决方案中,该解决方案仍然必须列出我要解析的每个键,我已经使用JSON_query解决了它,这是一个更简单的解决方案,但问题是我有40多个键要解析,效率低下将它们一一列出。我正在寻找一个可以解析 JSON 列而无需指定 JSON 字符串中的每个键的函数。

solution with json_query

【讨论】:

  • 这不是一个答案,而是一个评论......好吧,SQL-Server 的一个原则是:引擎必须事先没有结果集的结构。当您想使用 JSON 内部作为列名时,您必须告诉引擎该做什么...您的解决方案(链接)绝不简单或更有效。我的解决方案完全返回您在问题中放置的预期输出。如果您需要其他内容,请不要更改此问题,而是通过接受其中一个答案并开始一个新问题来关闭它。否则谷歌“变色龙问题”。快乐编码...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-30
  • 2016-05-10
  • 2022-06-14
  • 1970-01-01
相关资源
最近更新 更多