I have JSON like this:
{
"_key": {
"id": "3b8d1ed7-c3ec-32ec-a083-2ddc17152e94",
"rootId": "15c85327-9628-3685-b84a-375b546ba92a",
},
"employeeInfo": {
"idNumber": "3",
"gender": "Male",
"age": 20,
....
},
"product": {
"plan": "prod",
"class": "1",
"_type": "Product",
...
}
}
And I want to receive new JSON with desired fields. I'm using next query:
SELECT
'{ "employeeInfo": {"age: ' +
JSON_VALUE(info, '$.employeeInfo.age') + ', "gender": ' +
JSON_VALUE(info, '$.employeeInfo.gender') + ' }' AS info
FROM
item.[Item] AS c
INNER JOIN
(SELECT "rootId", MAX("revisionNo") AS maxRevisionNo
FROM item."Item"
WHERE "rootId" = 'E3B455EF-D48E-338C-B6D4-FFD8B41243F9'
GROUP BY "rootId") AS subquery ON c."rootId" = subquery."rootId";
And I get this response:
{ "employeeInfo": {"age: 38, "gender": Female }
But it seems JSON_VALUE
doesn't return type, so Female is without quotes. I don't know what fields will be requested, so I can't add quotes myself. How can I execute a query to return values with their types. I.e. I expect next response:
{ "employeeInfo": {"age: 38, "gender": "Female" }
I'm using this SQL Server version:
Microsoft Azure SQL Edge Developer (RTM) - 15.0.2000.1552 (ARM64)
UPD: I'm already have solution for postgres:
SELECT jsonb_strip_nulls(json_build_object('employee_info', json_build_object('age', c."info"->'employeeInfo' -> 'age', 'gender', c."info"->'employeeInfo' -> 'gender'), 'product', c."info"->'product')::jsonb) as info ...
And also need to build a request for sql-server. I will build this request dynamically when receive field names.
UPD2: I've created one more question which contains additional requirements. I need "product.plan" field also and have possibility to add any other fields How to build JSON with selected fields from JSON columns in SQL server keeping fields type
A slightly better syntax for @zhorov's excellent answer.
ROOT
parameter instead of adding it to the column name.$.employeeInfo
directly into OPENJSON
SELECT
info = (
SELECT
j.age,
j.gender
FROM OPENJSON(i.info, '$.employeeInfo')
WITH (
age sql_variant,
gender varchar(10)
) j
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, ROOT('employeeInfo')
)
FROM (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY i.rootId ORDER BY i.revisionNo DESC)
FROM item.Item AS i
WHERE i.rootId = 'E3B455EF-D48E-338C-B6D4-FFD8B41243F9'
) i
WHERE i.rn = 1;
If you want to do it completely dynamically then you need OPENJSON
without a schema. Then rebuild it using a combination of STRING_AGG
CONCAT
and STRING_ESCAPE
.
SELECT
info = (
SELECT
CONCAT(
'{"employeeInfo":{',
STRING_AGG(
CONCAT(
'"',
STRING_ESCAPE(j.[key], 'json'),
'":',
IIF(j.type = 1, CONCAT('"', STRING_ESCAPE(j.value, 'json'), '"'), j.value)
),
','
),
'}}'
)
FROM OPENJSON(i.info, '$.employeeInfo') j
WHERE j.[key] IN ('age', 'gender')
)
FROM (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY i.rootId ORDER BY i.revisionNo DESC)
FROM item.Item AS i
WHERE i.rootId = 'E3B455EF-D48E-338C-B6D4-FFD8B41243F9'
) i
WHERE i.rn = 1;