TSQL——为子对象(不是数组)中的未知/动态键提取JSON值

TSQL——为子对象(不是数组)中的未知/动态键提取JSON值,json,sql-server,tsql,Json,Sql Server,Tsql,我正在使用DataTables、DataTables编辑器、JavaScript和MSSQL 2016 我想在SQL Server中解析此字符串: { "action":"edit", "data": { "2019-08-03":{ "Description":"sdfsafasdfasdf", "FirstFroz

我正在使用DataTables、DataTables编辑器、JavaScript和MSSQL 2016

我想在SQL Server中解析此字符串:

{
    "action":"edit",
    "data": { 
                "2019-08-03":{ 
                                "Description":"sdfsafasdfasdf",
                                "FirstFrozenStep":"333"
                             }
            }
}
{
     "action":"edit",
     "DT_RowId":"2019-08-03",
     "Description":"sdfsafasdfasdf",
     "FirstFrozenStep":"333"
}
我不知道如何访问密钥“2019-08-03”。这表示数据表编辑器中的主键或
DT_RowId
。它是动态的。。。它可能会改变

历史上,我只是将JavaScript中的数据处理为平面对象,这在SQL Server中更容易解析:

{
    "action":"edit",
    "data": { 
                "2019-08-03":{ 
                                "Description":"sdfsafasdfasdf",
                                "FirstFrozenStep":"333"
                             }
            }
}
{
     "action":"edit",
     "DT_RowId":"2019-08-03",
     "Description":"sdfsafasdfasdf",
     "FirstFrozenStep":"333"
}
但是,我想知道如何使用
json\u query
json\u value
openjson()
深入到上面提到的“动态”键,然后访问其值

以下是我所有失败的尝试:

declare
    @jsonRequest nvarchar(max) = '{"action":"edit","data":{"2019-08-03":{"Description":"sdfsafasdfasdf","FirstFrozenStep":"333"}}}'
    ,@json2 nvarchar(max) = '{"2019-08-03":{"Description":"sdfsafasdfasdf","FirstFrozenStep":"333"}}'
    ,@jsonEASY nvarchar(max) = '{"action":"edit","DT_RowId":"2019-08-03","Description":"sdfsafasdfasdf","FirstFrozenStep":"333"}'


    select
        json_value(@jsonRequest, '$.action') as [action]
        --,json_value(@jsonRequest, '$.data.[0]') as [action]
        --,json_query(@jsonRequest, '$.data[0]')
        --,json_query(@jsonRequest, '$.data.[0]')
        --,json_query(@jsonRequest, '$.data[0].Description')
        --,json_query(@jsonRequest, '$.data.Description')
        --,json_query(@jsonRequest, '$.data.[0].Description')


select
    [Key]
    ,Value
    ,Type
    --,json_query(value, '$')
from
    openjson(@jsonRequest)



SELECT x.[Key], x.[Value]
FROM OPENJSON(@jsonRequest, '$') AS x;

select
    x.[Key]
    ,x.[Value]
    --,json_query(x.value, '$')
    --,(select * from openjson(x.value))
FROM OPENJSON(@jsonRequest, '$') AS x;

SELECT x.[Key], x.[Value]
FROM OPENJSON(@json2, '$') AS x;


    select
        json_value(@jsonEASY, '$.action') as [action]
        ,json_value(@jsonEASY, '$.DT_RowId') as [DT_RowId]
        ,json_value(@jsonEASY, '$.Description') as [Description]

您可以使用OUTER APPLY进入JSON的下一个级别:

SELECT L1.[key], L2.[key], L2.[value]
FROM openjson(@json,'$.data') AS L1
OUTER APPLY openjson(L1.[value]) AS L2
它将返回:

key         key             value  
2019-08-03  Description     sdfsafasdfasdf  
2019-08-03  FirstFrozenStep 333

您可以使用OUTER APPLY进入JSON的下一个级别:

SELECT L1.[key], L2.[key], L2.[value]
FROM openjson(@json,'$.data') AS L1
OUTER APPLY openjson(L1.[value]) AS L2
它将返回:

key         key             value  
2019-08-03  Description     sdfsafasdfasdf  
2019-08-03  FirstFrozenStep 333

最明确和类型安全的方法可能是:

我用两个动态键定义JSON

--询问

SELECT A.[action]
      ,B.[key]
      ,C.*
FROM OPENJSON(@json) WITH([action]  NVARCHAR(100)
                         ,[data]    NVARCHAR(MAX) AS JSON) A
OUTER APPLY OPENJSON(A.[data]) B 
OUTER APPLY OPENJSON(B.[value]) WITH([Description] NVARCHAR(100)
                                     ,FirstFrozenStep INT) C;
结果

action  key         Description     FirstFrozenStep
edit    2019-08-03  sdfsafasdfasdf  333
edit    2019-08-04  blah4           444
简而言之:

  • 第一个
    OPENJSON()
    将返回别名
    A
    下的两个一级键。
    数据
    元素以JSON的形式返回
    ,允许以后继续此操作
  • 第二个
    OPENJSON()
  • 第三个
    OPENJSON()
    现在将
    B.[value]
    作为输入
WITH
-子句允许读取隐式旋转并键入的内部元素


一般情况下:在通用数据容器中,使用描述性部分作为内容并不是一个好主意。这是可能的,看起来可能很聪明,但最好将日期作为内容放在
日期
键中

最明确和类型安全的方法可能是:

我用两个动态键定义JSON

--询问

SELECT A.[action]
      ,B.[key]
      ,C.*
FROM OPENJSON(@json) WITH([action]  NVARCHAR(100)
                         ,[data]    NVARCHAR(MAX) AS JSON) A
OUTER APPLY OPENJSON(A.[data]) B 
OUTER APPLY OPENJSON(B.[value]) WITH([Description] NVARCHAR(100)
                                     ,FirstFrozenStep INT) C;
结果

action  key         Description     FirstFrozenStep
edit    2019-08-03  sdfsafasdfasdf  333
edit    2019-08-04  blah4           444
简而言之:

  • 第一个
    OPENJSON()
    将返回别名
    A
    下的两个一级键。
    数据
    元素以JSON
    的形式返回
    ,允许以后继续此操作
  • 第二个
    OPENJSON()
  • 第三个
    OPENJSON()
    现在将
    B.[value]
    作为输入
WITH
-子句允许读取隐式旋转并键入的内部元素


一般情况下:在通用数据容器中,使用描述性部分作为内容并不是一个好主意。这是可能的,看起来可能很聪明,但最好将日期作为内容放在
日期
键中

我收到这样的消息:“关键字“with”附近的语法不正确。如果此语句是公共表表达式、xmlnamespaces子句或更改跟踪上下文子句,则前一个语句必须以分号终止。”@raydlevel5,但不是因为OPENJSON语句中的with。这一定是其他东西…对不起,我执行时附加到一个数据库有错误的“版本”。。。我会回来报到的。谢谢。我接受你的答案,因为它是有效的,你已经解释了一个工具,我可以在未来使用(外部应用)。我完全同意你反对使用通用密钥的说法;但是,您看到的请求是“原始”的,由DataTables编辑器生成。因为我可以选择在请求到达SQL之前对其进行操作,所以我可能会继续“扁平化”数据以使其更易于解析。。。。但是你已经为我们提供了一种获得通用密钥的方法@raydlevel5还有一个反对内容键的理由:它们在任何情况下都是nvarchar。普通内容是以键入的方式(例如,通过格式化日期的方式)输入的,您可以以类型安全的方式阅读。我收到以下消息:“关键字“with”附近的语法不正确。如果此语句是公共表表达式、xmlnamespaces子句或更改跟踪上下文子句,则前一条语句必须以分号终止。“@raydlevel5,但不是因为OPENJSON语句中的with。这一定是其他原因……抱歉,我在附加到“版本”错误的数据库时执行了此语句"... 我会回来报到的。谢谢。我接受你的答案,因为它是有效的,你已经解释了一个工具,我可以在未来使用(外部应用)。我完全同意你反对使用通用密钥的说法;但是,您看到的请求是“原始”的,由DataTables编辑器生成。因为我可以选择在请求到达SQL之前对其进行操作,所以我可能会继续“扁平化”数据以使其更易于解析。。。。但是你已经为我们提供了一种获得通用密钥的方法@raydlevel5还有一个反对内容键的理由:它们在任何情况下都是nvarchar。普通内容是以键入的方式(例如,通过格式化日期的方式)输入的,您可以以类型安全的方式读取。