使用openjson和/或json_value解析TSQL中的未知JSON路径

时间:2019-05-23 14:43:57

标签: json tsql

我有一个看起来像这样的传入数据结构:

declare @json nvarchar(max) = '{
    "action": "edit",
    "data": {
        "2077-09-02": {
            "Description": "some stuff",
            "EffectDate": "2077-1-1"
        }
    }
}';

长话短说,我认为TSQL讨厌这种json结构,因为无论我尝试了什么,除“ action”外,我无法获得任何其他值。

{data}对象包含另一个对象{2077-09-02}。 “ 2077-09-02” 总是不同的。我不能指望那会是什么日期。

这有效:

select json_value(@json, '$.action');
尝试获取其他值时,

没有有效。

select json_value(@json, '$.data');  --returns null

select json_value(@json, '$.data[0]'); --returns null

select json_value(@json, 'lax $.data.[2077-09-02].Description');
--JSON path is not properly formatted. Unexpected character '[' is found at position 11.

select json_value(@json, 'lax $.data.2077-09-02.Description');
--JSON path is not properly formatted. Unexpected character '2' is found at position 11.

如何获得其他值? JSON对于TSQL来说还不够完善吗?

2 个答案:

答案 0 :(得分:1)

使用双引号代替[]JSON Path使用JavaScript的约定,其中字符串用双引号引起来。文档的示例包含此路径$."first name"

在这种情况下:

select json_value(@json,'$.data."2077-09-02".Description');

返回:

some stuff

对于其他调用,JSON_VALUE仅可以返回标量值,而不能返回对象。您需要使用JSON_QUERY提取JSON对象,例如:

select json_query(@json,'$.data."2077-09-02"');

返回:

{
    "Description": "some stuff",
    "EffectDate": "2077-1-1"          
}

答案 1 :(得分:1)

将基于文本的容器的声明部分用作数据绝不是一个好主意。 "2077-09-02"是有效的json键,但很难查询。

您可以尝试以下方法:

declare @json nvarchar(max) = '{
    "action": "edit",
    "data": {
        "2077-09-02": {
            "Description": "some stuff",
            "EffectDate": "2077-1-1"
        }
    }
}';

SELECT A.[action]
      ,B.[key] AS DateValue
      ,C.*
FROM OPENJSON(@json)
WITH([action] NVARCHAR(100)
    ,[data]   NVARCHAR(MAX) AS JSON) A
CROSS APPLY OPENJSON(A.[data]) B 
CROSS APPLY OPENJSON(B.[value]) 
WITH (Description NVARCHAR(100)
     ,EffectDate DATE) C;

结果

action  DateValue   Description EffectDate
edit    2077-09-02  some stuff  2077-01-01

想法:

  • 第一个OPENJSON将返回actiondata
  • 我使用WITH子句告诉引擎,action是一个简单值,而data是嵌套的JSON
  • 下一个OPENJSON进入data
  • 我们现在可以使用B.[key]来获取json键的值
  • 现在我们需要另一个OPENJSON来进入 {}内部的列。

但是:如果此JSON受您控制,建议您更改其结构。