使用T-SQL的动态JSON解析

使用T-SQL的动态JSON解析,json,sql-server,tsql,sql-server-2017,sql-server-json,Json,Sql Server,Tsql,Sql Server 2017,Sql Server Json,我有一个高度非结构化的JSON字符串,作为调用REST API的响应: { “信息”:“测试Json结构”, “所有者”:“自有”, “管理对象”:[{ “名称”:“设备1”, “类别”:“A” }, { “名称”:“设备2”, “类别145”:“Ax01”, “类别11”:“B”, “类型_125478”:{ “模型”:“1”, “制造商”:“外部” }, “类型_SD”:{ “型号”:“00”, “制造商”:“内部” } }, { “名称”:“设备3”, “x类”:“Cx11”, “类”:“

我有一个高度非结构化的JSON字符串,作为调用REST API的响应:

{
“信息”:“测试Json结构”,
“所有者”:“自有”,
“管理对象”:[{
“名称”:“设备1”,
“类别”:“A”
}, {
“名称”:“设备2”,
“类别145”:“Ax01”,
“类别11”:“B”,
“类型_125478”:{
“模型”:“1”,
“制造商”:“外部”
},
“类型_SD”:{
“型号”:“00”,
“制造商”:“内部”
}
}, {
“名称”:“设备3”,
“x类”:“Cx11”,
“类”:“C8Y”,
“类型”:{
“型号”:“1x”,
“制造商”:“内部”
}
}
]
}

如何使用T-SQL动态解析此对象,以便所有子元素都表示表的列?更重要的是,如何处理
类型
类型_125478
类型_SD
对象,它们实际上具有相同的结构(
型号,制造商
),但它们的名称不同。还请记住,设备可能会发送一个新的标识符(
Type_XYZ
),该标识符以前不存在,但幸运的是具有相同的结构(
型号,制造商
)。

您可以使用类似的方法将整个批次分解为表格结构,然后继续执行此操作(需要SQL Server版本v2016+):

--询问

SELECT A.info
      ,A.[Owner]
      ,C.[key] AS TagName
      ,CASE WHEN D.Model IS NULL THEN C.[value] END AS TagValue 
      ,D.Model
      ,D.Manufacturer
FROM OPENJSON(@YourJSON)
WITH(info NVARCHAR(MAX)
    ,[Owner] NVARCHAR(MAX)
    ,managedObjects NVARCHAR(MAX) AS JSON) A
OUTER APPLY OPENJSON(A.managedObjects) B
OUTER APPLY OPENJSON(B.[value]) C
OUTER APPLY OPENJSON(CASE WHEN ISJSON(C.[value])=1 THEN C.[value] END) 
WITH (Model NVARCHAR(MAX)
     ,Manufacturer NVARCHAR(MAX))D;
--结果

+---------------------+------------+-------------+----------+-------+--------------+
| info                | Owner      | TagName     | TagValue | Model | Manufacturer |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Name        | Device1  |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Class       | A        |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Name        | Device2  |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Class_145   | Ax01     |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Class_11    | B        |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Type_125478 |          | 1     | External     |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Type_SD     |          | 00    | Internal     |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Name        | Device3  |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Class_x     | Cx11     |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Class_T     | C8Y      |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Type        |          | 1x    | Internal     |
+---------------------+------------+-------------+----------+-------+--------------+
提示:您可以将
B.[key]
作为对象标识符添加到结果中

简言之,这个想法

  • 我们使用第一个
    OPENJSON
    进入您的JSON。
    WITH
    -子句允许将JSON道具作为列进行寻址。我们将
    managedObejcts
    作为JSON本身返回
  • 我们再使用一个
    OPENJSON
    来深入研究托管对象
  • 这将返回一个对象数组。我们可以将
    传递到另一个
    OPENJSON
  • 每当
    值本身可以解释为JSON时,我们就使用另一个
    OPENJSON
    ,这次再次使用
    with
    -子句将内部道具作为列

您可以将此结果插入表格(声明、临时、物理…),然后继续使用此易于阅读的集合。

您可以使用类似的方法将整个批次分解为表格结构,然后继续此操作(需要SQL Server版本v2016+):

--询问

SELECT A.info
      ,A.[Owner]
      ,C.[key] AS TagName
      ,CASE WHEN D.Model IS NULL THEN C.[value] END AS TagValue 
      ,D.Model
      ,D.Manufacturer
FROM OPENJSON(@YourJSON)
WITH(info NVARCHAR(MAX)
    ,[Owner] NVARCHAR(MAX)
    ,managedObjects NVARCHAR(MAX) AS JSON) A
OUTER APPLY OPENJSON(A.managedObjects) B
OUTER APPLY OPENJSON(B.[value]) C
OUTER APPLY OPENJSON(CASE WHEN ISJSON(C.[value])=1 THEN C.[value] END) 
WITH (Model NVARCHAR(MAX)
     ,Manufacturer NVARCHAR(MAX))D;
--结果

+---------------------+------------+-------------+----------+-------+--------------+
| info                | Owner      | TagName     | TagValue | Model | Manufacturer |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Name        | Device1  |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Class       | A        |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Name        | Device2  |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Class_145   | Ax01     |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Class_11    | B        |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Type_125478 |          | 1     | External     |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Type_SD     |          | 00    | Internal     |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Name        | Device3  |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Class_x     | Cx11     |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Class_T     | C8Y      |       |              |
+---------------------+------------+-------------+----------+-------+--------------+
| Test Json Structure | Self-Owned | Type        |          | 1x    | Internal     |
+---------------------+------------+-------------+----------+-------+--------------+
提示:您可以将
B.[key]
作为对象标识符添加到结果中

简言之,这个想法

  • 我们使用第一个
    OPENJSON
    进入您的JSON。
    WITH
    -子句允许将JSON道具作为列进行寻址。我们将
    managedObejcts
    作为JSON本身返回
  • 我们再使用一个
    OPENJSON
    来深入研究托管对象
  • 这将返回一个对象数组。我们可以将
    传递到另一个
    OPENJSON
  • 每当
    值本身可以解释为JSON时,我们就使用另一个
    OPENJSON
    ,这次再次使用
    with
    -子句将内部道具作为列

您可以将此结果插入表(声明、临时、物理…)并继续使用此易于阅读的集合。

因此,每次查询的结果都会有不同的列数,这取决于您是否得到许多
“Class_145”
“Class_11”
s或否?我认为最好使用诸如type\u name和type\u value之类的类型,而不是许多列,因为您只能使用固定的resultset@GSerg一种解决方案是创建完整的列集,与json匹配的列将具有值,其他列将具有NULL。。这就是R在解析这样的动态字符串时所做的。问题是如何在T中做同样的事情-SQL@astentx这无疑会简化问题,但我无法控制数据源发送数据的方式。哪个版本的SQL Server?v2016引入了JSON支持。因此,每次查询的结果都会有不同的列数,这取决于您是否得到许多
“Class_145”
“Class_11”
s或否?我认为最好使用诸如type\u name和type\u value之类的类型,而不是许多列,因为您只能使用固定的resultset@GSerg一种解决方案是创建完整的列集,与json匹配的列将具有值,其他列将具有NULL。。这就是R在解析这样的动态字符串时所做的。问题是如何在T中做同样的事情-SQL@astentx这无疑会简化问题,但我无法控制数据源发送数据的方式。哪个版本的SQL Server?JSON支持是在v2016中引入的。感谢@Shnugo在我使用SQL Server 2017时实际起到了作用。感谢@Shnugo在我使用SQL Server 2017时实际起到了作用。。