Select last value from Json array

前端 未结 3 806
慢半拍i
慢半拍i 2021-01-22 16:00

I need to get the last item in an array from a JSON format. I have this JSON.

  @json =   
  N\'{ 
        \"solution\": \"xxxxxxxxxxxxxxxxxxxxx\",
        \"opt         


        
相关标签:
3条回答
  • 2021-01-22 16:36

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

    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))
    
    0 讨论(0)
  • 2021-01-22 16:42

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

    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.

    0 讨论(0)
  • 2021-01-22 16:51

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

    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.

    0 讨论(0)
提交回复
热议问题