Select last value from Json array

[亡魂溺海] 提交于 2019-12-02 08:59:44

问题


I need to get the last item in an array from a JSON format. I have this 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"
            }
        ],
    }'  

And I would like to get

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

How can I achieve that result?


回答1:


You can try this

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;

The result

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

Some explanation

FROM OPENJSON will dive into your JSON and find the top-level elements. We fetch solution as is and we state AS JSON for options to specify, that this value will be treated as JSON later on.

The CROSS APPLY will call OPENJSON again, but this time against the options and we will get an array back. The column key is the ordinal position within the array, so we can use TOP 1 and ORDER BY key DESC to get the last element in the array.

Before we can re-assemble this query to a JSON we have to wrap B.value with JSON_QUERY(). Otherwise we would see escaped characters like \t or \r\n within the JSON. The reason: Without this, the JSON-string would not be taken as a JSON-string but as any other string and would be packed into the result as one single text value.




回答2:


You can either shred with OPENJSON and re-assemble the document FOR JSON (see @digital.aaron's answer), or use JSON_MODIFY, like this:

 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

Outputs

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

Note that the JSON_QUERY function is also used for parsing a string into a JSON fragment. Without that, the value in @options would be inserted as a single string value, instead of a json object.




回答3:


First, your JSON string is malformed. You need to remove the comma after the closing array bracket.

So let's declare our variable:

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"
            }
        ]
    }'

Now you can use a combination of OPENJSON() and FOR JSON to get the last record in the array.

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))

EDIT:

Or you can use this query, if you don't want to order by any of the node values:

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))


来源:https://stackoverflow.com/questions/52703674/select-last-value-from-json-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!