Extract object and scalar value via single function - sql

I have to write a query in SQL to extract a JSON path's value. Now the issue is that path's ultimate value can either be a JSON object or scalar value. But in SQL Server, to get the object and scalar value JSON_QUERY and JSON_VALUE functions should be used respectively. My issue is that I want to write the same query which returns both types of values. Is there any way in which this can be achieved?

You can use OPENJSON function to get the values for a given path $.foo.bar like so:
CREATE TABLE t(
id INT IDENTITY NOT NULL PRIMARY KEY,
json VARCHAR(MAX)
);
INSERT INTO t(json) VALUES
('{ "foo": { "bar": 123 } }'),
('{ "foo": { "bar": "x" } }'),
('{ "foo": { "bar": [1] } }'),
('{ "foo": { "bar": { "baz": 1 } } }');
SELECT *
FROM t
CROSS APPLY OPENJSON(json, '$.foo')
WHERE [key] = 'bar';
The result will contain these important columns:
key: name of the key below $.foo which could be used inside WHERE clause
value: the value for the key having datatype = NVARCHAR(MAX)
type: the type of the value having datatype = INT (see documentation)
Demo on db<>fiddle

Related

Handle partial Stringified Partial Key-value JSON VARIANT on SQL

I have a variant object like the below:
{
"build_num": "111",
"city_name": "Paris",
"rawData": "\"sku\":\"AAA\",\"price\":19.98,\"currency\":\"USD\",\"quantity\":1,\"size\":\"\"}",
"country": "France"
}
So you can see that parts of it are regular key-value pairs like build num and city name, but then we have raw data which its value is a stringified version of a JSON
I would like to create a variant from this that will look like:
{
"build_num": "111",
"city_name": "Paris",
"rawData": {
"sku":"AAA",
"price":19.98,
"currency":"USD",
"quantity":1}
"country": "France"
}
AND I would like to do this all in SQL (Snowflake) - is that possible?
so to poke the "data" into I have used a CTE, and escaped the sub json, so it is in the DB as you describe. I also had to add the missing start of object token {, to make rawData valid.
WITH data AS (
SELECT parse_json(json) as json
FROM VALUES
('{"build_num": "111","city_name": "Paris","country": "France","rawData": "{\\"sku\\":\\"AAA\\",\\"price\\":19.98,\\"currency\\":\\"USD\\",\\"quantity\\":1,\\"size\\":\\"\\"}"}')
v( json)
)
SELECT
json,
json:rawData as raw_data,
parse_json(raw_data) as sub_json,
OBJECT_INSERT(json, 'rawData', sub_json, true) as all_json
FROM data;
so this show step by step transforming the data, parsing it via PARSE_JSON, and re inject via OBJECT_INSERT the result into the original object.
WITH data AS (
SELECT parse_json(json) as json
FROM VALUES
('{"build_num": "111","city_name": "Paris","country": "France","rawData": "{\\"sku\\":\\"AAA\\",\\"price\\":19.98,\\"currency\\":\\"USD\\",\\"quantity\\":1,\\"size\\":\\"\\"}"}')
v( json)
)
SELECT
OBJECT_INSERT(json, 'rawData', parse_json(json:rawData), true) as all_json
FROM data;
TRY_PARSE_JSON will clear off additional slashes from JSON element and below is reference:
select
column1 as n,
try_parse_json(column1) as v
from
values
(
'{
"build_num": "111",
"city_name": "Paris",
"rawData": "{\"sku\":\"AAA\",\"price\":19.98,\"currency\":\"USD\",\"quantity\":1,\"size\":\"\"}",
"country": "France"}'
) as vals;

MSSQL Query JSON displays Null value

I have a table PublicRelations with a column called Students in a SQL Server database called Subjects.
[
{ "Label": "Name", "ColumnValue": "Trudie" },
{ "Label": "Class", "ColumnValue": "PublicRelations" },
{ "Label": "Room", "ColumnValue": "8049" },
{ "Label": "HttpPath", "ColumnValue": "https://www.google.com/" }
]
I only get NULL when I run the below query using the Json_value. I'd like to get it to display the value from the array. I believe this may have to do with the 4000 character limit?
SELECT [StuduentID],
[Students],
--JSON_VALUE([Students],'$.ColumnValue') AS Name --Only returns NULL
FROM [Subjects].[dbo].[PublicRelations] c
CROSS APPLY OPENJSON(c.Students)
WITH ( Name int '$.Name',
Value nvarchar(255) '$.ColmunValue'
) AS jsonValues
WHERE jsonValues.ColumnValue = 'Trudie'
The query works and I can find what I need, but again, I only get NULL when I want to display that part of the JSON column in my results.
The statement is wrong and you has the following issues (as #MartinSmith already mentioned):
Syntax error - '$.ColmunValue' should be '$.ColumnValue'.
Wrong schema definition (the WITH clause) - I can't see Name key in the input JSON.
Wrong use of JSON_VALUE() - this function extracts scalar value from a JSON string, so JSON_VALUE([Students],'$.ColumnValue') returns NULL with this JSON input in lax mode.
You may try with the following statement (based on the statement in the question):
Table:
CREATE TABLE PublicRelations (
StudentID int,
Students nvarchar(1000))
INSERT INTO PublicRelations (StudentID, Students)
VALUES (1, N'[
{ "Label": "Name", "ColumnValue": "Trudie" },
{ "Label": "Class", "ColumnValue": "PublicRelations" },
{ "Label": "Room", "ColumnValue": "8049" },
{ "Label": "HttpPath", "ColumnValue": "https://www.google.com/" }
]')
Statement:
SELECT p.StudentID, j.*
FROM [PublicRelations] p
CROSS APPLY OPENJSON(p.Students) WITH (
Name nvarchar(50) '$.Label',
Value nvarchar(255) '$.ColumnValue'
) j
WHERE EXISTS (
SELECT 1
FROM OPENJSON(p.Students) WITH (Value nvarchar(255) '$.ColumnValue')
WHERE Value = N'Trudie'
) AND (j.Name IN ('Name', 'Class', 'Room'))
Result:
StudentID Name Value
1 Name Trudie
1 Class PublicRelations
1 Room 8049

How to write a select query to get the index value from Json object

I have the below JSON object. I need to write a select query to get the index values of Object JSON array. Kind of getting the sequence value.
{
"Model": [
{
"ModelName": "Test Model",
"Object": [
{
"ID": 1,
"Name": "ABC",
},
{
"ID": 11,
"Name": "ABCD",
},
{
"ID": 15,
"Name": "ABCDE",
},
]
}]}
Expected Output:
Index_Value
1
2
3
If I understand the question correctly and you want to get the index of the items in the Object JSON array, you need to use OPENJSON() with default schema. The result is a table with columns key, value and type and in case of JSON array, the key column holds the index of each item in the array (0-based):
JSON:
DECLARE #json nvarchar(max) = N'{
"Model":[
{
"ModelName":"Test Model",
"Object":[
{
"ID":1,
"Name":"ABC"
},
{
"ID":11,
"Name":"ABCD"
},
{
"ID":15,
"Name":"ABCDE"
}
]
}
]
}'
Statement:
SELECT CONVERT(int, j2.[key]) + 1 AS item_id
FROM OPENJSON (#json, '$.Model') j1
CROSS APPLY OPENJSON(j1.[value], '$.Object') j2
But if you want to get the values of the ID keys in the Object JSON array, the statement is different:
SELECT j2.ID
FROM OPENJSON (#json, '$.Model') j1
CROSS APPLY OPENJSON(j1.[value], '$.Object') WITH (
ID int '$.ID'
) j2
Note, that you need two OPENJSON() calls, because the input JSON has nested array structure. Of course, if Model JSON array has always one item, you may simplify the statement using an appropriate path:
SELECT CONVERT(int, [key]) + 1 AS item_id
FROM OPENJSON (#json, '$.Model[0].Object')
Finally, to get index, ID and Name, you should use the following statement, which assumes, that $.Model JSON array has more than one item and defines ID and Name columns with the appropraite data types:
SELECT
CONVERT(int, j2.[key]) + 1 AS ItemID,
j3.ID, j3.Name
FROM OPENJSON (#json, '$.Model') j1
CROSS APPLY OPENJSON(j1.[value], '$.Object') j2
CROSS APPLY OPENJSON(j2.[value], '$') WITH (
ID int '$.ID',
Name varchar(50) '$.Name'
) j3
DECLARE #json nvarchar(max) = N'{
"Model":[
{
"ModelName":"Test Model",
"Object":[
{
"ID":1,
"Name":"ABC"
},
{
"ID":11,
"Name":"ABCD"
},
{
"ID":15,
"Name":"ABCDE"
}
]
}
]
}'
declare #i int=0;
SELECT
j2.ID, j2.Name
FROM OPENJSON (#json, '$.Model') j1
CROSS APPLY OPENJSON(j1.[value],concat('$.Object[',#i,']')) WITH (
ID i`enter code here`nt '$.ID', Name varchar(100) '$.Name'
) j2
Results:-
ID
Name
11
ABCD
you can select the key columns in select clause no need to mention in with of crossjoin.
SELECT
distinct t.id,
JSON_VALUE(AttsData.[value], '$.address') as address,
JSON_VALUE(AttsData.[value], '$.name') as name,
JSON_VALUE(AttsData.[value], '$.owner_name') as owner_name,
JSON_VALUE(AttsData.[value], '$.project') as project
,CONVERT(int, AttsData.[key]) index_id
FROM mytablewithjsonfeild t
CROSS APPLY OPENJSON (t."jsonfeild",N'$.parentkey') as AttsData
Above query, from the table I have cross joined the JSON field. and in select statement i have taken the specific keys.
and CONVERT(int, AttsData.[key]) to get the index of the elements

JSON_VALUE SQL Server function not returning all values

I have this nvarchar field with a JSON like this:
{"BOARD":"QC_Reference_Phone","SERIAL":"LGM700c2eee454","VERSION.INCREMENTAL":"1901817521542","CPU_ABI2":"armeabi","HOST":"CLD-BLD3-VM1-16","TIME":"1547801577000","MODEL":"LG-M700","MANUFACTURER":"LGE","USER":"jenkins","CPU_ABI":"armeabi-v7a","BRAND":"lge","DISPLAY":"OPM1.171019.026","FINGERPRINT":"lge/mh_global_com/mh:8.1.0/OPM1.171019.026/1901817521542:user/release-keys","HARDWARE":"mh","PRODUCT":"mh_global_com","BOOTLOADER":"unknown","VERSION.RELEASE":"8.1.0","ID":"OPM1.171019.026","UNKNOWN":"unknown","TYPE":"user","VERSION.SDK.NUMBER":"27","TAGS":"release-keys"}
And so my syntax is:
select JSON_VALUE(DeviceHardwareData,'$.VERSION.SDK.NUMBER') SDKVersion_nbr
FROM MyTable
It will work with all the other values within the JSON field but for "VERSION.SDK.NUMBER".
It returns a NULL Result for every row in my table.
I can actually get the value with the OPENJSON function, but I would like to know why it's specifically not returning the value for that attribute using JSON_Value
It doesn't work as you expect because in JSON Path syntax, the full stop character means "going one level down to a nested element under the following name". In order to extract the value with your path expression, your JSON structure should resemble the following:
"VERSION": {
"SDK": {
"NUMBER": 14
}
}
However, enclosing the element name in doublequotes in the path expression apparently does the trick:
declare #j nvarchar(max) = N'{
"VERSION.SDK.NUMBER": "27",
"VERSION": {
"SDK": {
"NUMBER": 14
}
}
}';
select json_value(#j, '$."VERSION.SDK.NUMBER"') as [TopValue],
json_value(#j, '$.VERSION.SDK.NUMBER') as [NestedValue];

SQL Server - JSON type enumeration

Given
declare #json varchar(max)='{
"name":"John",
"age":30,
"cars": [
{ "make":"Ford", "models":[ "Fiesta", "Focus", "Mustang","Vintage"] ,"price":[1100,200,300,999]},
{ "make":"BMW", "models":[ "320", "X3", "X5" ] },
{ "make":"Fiat", "models":[ "500", "Panda" ] }
] }';
The query
select * from openjson(#json,'$')
returns 3 columns:
key value type
I haven't found an enumeration of the type column values and their corresponding meaning.
Please point me in the right direction; thanks.
From the MSDN page for OPENJSON:
Value of the Type column JSON data type
0 null
1 string
2 int
3 true/false
4 array
5 object