从Json数组中选择最后一个值

时间:2018-10-08 13:43:33

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

我需要从JSON格式获取数组中的最后一项。我有这个JSON。

  @json =   
  N'{ 
        "solution": "xxxxxxxxxxxxxxxxxxxxx",
        "options": [
            {
                "choice_id": 205073,
                "choice": "aaaa"
            },
            {
                "choice_id": 205074,
                "choice": "bbbb"
            },
            {
                "choice_id": 205075,
                "choice": "cccc"
            },
            {
                "choice_id": 205076,
                "choice": "dddd"
            }
        ],
    }'  

我想得到

  @json =   
  N'{ 
        "solution": "xxxxxxxxxxxxxxxxxxxxx",
        "options": {
              "choice_id": 205076,
              "choice": "dddd"
        }
    }

我如何获得那个结果?

3 个答案:

答案 0 :(得分:3)

您可以使用OPENJSON切碎并重新组装FOR JSON文档(请参阅@ digital.aaron的答案),也可以使用JSON_MODIFY,如下所示:

 declare @json nvarchar(max) =   
  N'{ 
        "solution": "xxxxxxxxxxxxxxxxxxxxx",
        "options": [
            {
                "choice_id": 205073,
                "choice": "aaaa"
            },
            {
                "choice_id": 205074,
                "choice": "bbbb"
            },
            {
                "choice_id": 205075,
                "choice": "cccc"
            },
            {
                "choice_id": 205076,
                "choice": "dddd"
            }
        ]
    }'  


declare @options nvarchar(max) = (
    select top 1 value 
    from openjson(@json,'$.options')
    order by [key] desc 
);

set @json = json_modify(@json, '$.options', json_query(@options))

select  @json

输出

{ 
        "solution": "xxxxxxxxxxxxxxxxxxxxx",
        "options": {
                "choice_id": 205076,
                "choice": "dddd"
            }
    }

请注意,JSON_QUERY函数还用于将字符串解析为JSON片段。否则,@ options中的值将作为单个字符串值而不是json对象插入。

答案 1 :(得分:3)

您可以尝试

DECLARE @json NVARCHAR(MAX) =   
N'{ 
    "solution": "xxxxxxxxxxxxxxxxxxxxx",
    "options": [
        {
            "choice_id": 205073,
            "choice": "aaaa"
        },
        {
            "choice_id": 205074,
            "choice": "bbbb"
        },
        {
            "choice_id": 205075,
            "choice": "cccc"
        },
        {
            "choice_id": 205076,
            "choice": "dddd"
        }
    ]
}';

SELECT TOP 1 
         A.solution
        ,JSON_QUERY(B.[value]) AS options
FROM OPENJSON(@json) WITH (solution nvarchar(max), options NVARCHAR(MAX) AS JSON) A
CROSS APPLY OPENJSON(A.options) B
ORDER BY B.[key] DESC
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER;

结果

{"solution":"xxxxxxxxxxxxxxxxxxxxx"
,"options":{
            "choice_id": 205076,
            "choice": "dddd"
           }
}

一些解释

FROM OPENJSON将深入您的JSON并找到顶级元素。我们按原样获取solution ,并声明AS JSON以供options指定,此值稍后将被视为JSON。

CROSS APPLY将再次调用OPENJSON,但是这次针对options,我们将得到一个数组。 key列是数组中的顺序位置,因此我们可以使用TOP 1ORDER BY key DESC来获取数组中的最后一个元素。

在将查询重新组合为JSON之前,我们必须用B.value包装JSON_QUERY()。否则,我们会在JSON中看到转义字符,例如\t\r\n。原因:如果没有此字符串,则JSON字符串将不会被当作JSON字符串,而会被当作任何其他字符串,并会作为一个单独的文本值打包到结果中。

答案 2 :(得分:2)

首先,您的JSON字符串格式错误。您需要在右方括号后面删除逗号。

所以我们声明一下变量:

DECLARE @json NVARCHAR(MAX) = N'{ 
        "solution": "xxxxxxxxxxxxxxxxxxxxx",
        "options": [
            {
                "choice_id": 205073,
                "choice": "aaaa"
            },
            {
                "choice_id": 205074,
                "choice": "bbbb"
            },
            {
                "choice_id": 205075,
                "choice": "cccc"
            },
            {
                "choice_id": 205076,
                "choice": "dddd"
            }
        ]
    }'

现在,您可以结合使用OPENJSON()FOR JSON来获取数组中的最后一条记录。

SELECT jsonfield = CAST((
                            SELECT TOP 1
                                j.solution
                                ,o.choice_id
                                ,o.choice
                            FROM
                                OPENJSON(@json)
                                WITH
                                (
                                    solution VARCHAR(MAX) '$.solution'
                                    ,options NVARCHAR(MAX) '$.options' AS JSON
                                ) j
                            CROSS APPLY
                                OPENJSON(options)
                                WITH
                                (
                                    choice_id INT '$.choice_id'
                                    ,choice VARCHAR(4) '$.choice'
                                ) o
                            ORDER BY o.choice_id DESC
                            FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
                        ) AS NVARCHAR(MAX))

编辑:

或者,如果您不想按任何节点值进行排序,也可以使用此查询:

SELECT jsonfield = CAST((
                            SELECT TOP 1
                                j.solution
                                --,o.*
                                ,c.choice_id
                                ,c.choice
                            FROM OPENJSON(@json)
                            WITH
                                (
                                    solution VARCHAR(MAX) '$.solution'
                                    ,options NVARCHAR(MAX) '$.options' AS JSON
                                ) j
                            CROSS APPLY OPENJSON(options) o
                            CROSS APPLY OPENJSON(o.Value) 
                            WITH (
                                    choice_id int '$.choice_id',
                                    choice varchar(4) '$.choice'
                                    ) c
                            ORDER BY [key] DESC
                            FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
                        ) AS NVARCHAR(MAX))