I need to get the last item in an array from a JSON format. I have this JSON.
@json =
N\'{
\"solution\": \"xxxxxxxxxxxxxxxxxxxxx\",
\"opt
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))
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.
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"
}
}
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.