How to return JSON property (SQL Server) - json

I am trying to select some data that is stored as JSON in SQL Server.
When I run isjson on the string, it returns 1.
However, I am unable to parse it.
declare #testStr nvarchar(max) = '{"order":{"address":{"shipToAddLine1":"1234 ABC Dr","shipToCityStZip":"Washington, DC 00000"}}}'
select isjson(#testStr) -- returns 1
select json_value(#testStr, '$'). -- returns null
select json_value(#testStr, '$.order') -- returns null
select #testStr -- returns entire string
How do I select the order node from the test string #testStr?

You can't use JSON_VALUE because that is not a scalar value, you need to use JSON_QUERY instead. An example of a scalar value would be the shipToAddLine1 field: select json_value(#testStr, '$.order.address.shipToAddLine1').
Using JSON_QUERY to get the order would be:
select json_query(#testStr, '$.order')
Result:
{"address":{"shipToAddLine1":"1234 ABC Dr","shipToCityStZip":"Washington, DC 00000"}}

You can use JSON_VALUE(), JSON_QUERY() and OPENJSON() to parse the input JSON. It's important to mention the following:
Function JSON_QUERY extracts an object or an array from a JSON string. If the value is not an object or an array, the result is NULL in lax mode and an error in strict mode.
Function JSON_VALUE extracts a scalar value from a JSON string. If the path points to not a scalar value, the result is NULL in lax mode and an error in strict mode
When you want to parse JSON string and get results as table, use OPENJSON table-valued function.
If you need to extract the order key you have two options - JSON_QUERY() or OPENJSON(). The following statement demonstrates how to extract a JSON object (from $.order key) and JSON values (from $.order.address.shipToAddLine1 and $.order.address.shipToCityStZip keys):
DECLARE #testStr nvarchar(max) =
N'{
"order":{
"address":{
"shipToAddLine1":"1234 ABC Dr",
"shipToCityStZip":"Washington, DC 00000"
}
}
}'
-- or
SELECT
shipToAddLine1 = JSON_VALUE(#testStr, '$.order.address.shipToAddLine1'),
shipToCityStZip = JSON_VALUE(#testStr, '$.order.address.shipToCityStZip'),
[order] = JSON_QUERY(#testStr, '$.order')
SELECT shipToAddLine1, shipToCityStZip, [order]
FROM OPENJSON(#testStr) WITH (
shipToAddLine1 nvarchar(100) '$.order.address.shipToAddLine1',
shipToCityStZip nvarchar(100) '$.order.address.shipToCityStZip' ,
[order] nvarchar(max) '$.order' AS JSON
)
Result:
shipToAddLine1 shipToCityStZip order
1234 ABC Dr Washington, DC 00000 {
"address":{
"shipToAddLine1":"1234 ABC Dr",
"shipToCityStZip":"Washington, DC 00000"
}
}

Related

How can I filter array values in a Json in Sql Server

How can I filter an array value without specifying the index in the array
This is my array
{
"level1":{
"level2":[
{
"level3":"test",
}
]
}
}
I want to retrive all rows that contains a level3 a value test.
Something like this
select * from Documents
where Json_Value(DocumentInfo, '$.level1.level2[X].level3') = 'test'
It this not possible in Sql Server?
Guessing of bit here, but use an EXISTS? This also assumes the JSON is valid, as the JSON in your question is not:
SELECT * --Should be a distinct column list
FROM dbo.Documents D
WHERE EXISTS (SELECT 1
FROM OPENJSON(D.DocumentInfo)
WITH (level1 nvarchar(MAX) AS JSON) L1
CROSS APPLY OPENJSON(L1.Level1)
WITH(level2 nvarchar(MAX) AS JSON) L2
CROSS APPLY OPENJSON(L2.Level2)
WITH (level3 varchar(10)) L3
WHERE L3.level3 = 'test');

Query SQL database with JSON Value

Here is my JSON:
[{"Key":"schedulerItemType","Value":"schedule"},{"Key":"scheduleId","Value":"82"},{"Key":"scheduleEventId","Value":"-1"},{"Key":"scheduleTypeId","Value":"2"},{"Key":"scheduleName","Value":"Fixed Schedule"},{"Key":"moduleId","Value":"5"}]
I want to query the database by FileMetadata column
I've tried this:
SELECT * FROM FileSystemItems WHERE JSON_VALUE(FileMetadata, '$.Key') = 'scheduleId' and JSON_VALUE(FileMetadata, '$.Value') = '82'
but it doesn't work!
I had it working with just a dictionary key/value pair, but I needed to return the data differently, so I am adding it with key and value into the json now.
What am I doing wrong?
With the sample data given you'd have to supply an array index to query the 1th element (0-based array indexes), e.g.:
select *
from dbo.FileSystemItems
where json_value(FileMetadata, '$[1].Key') = 'scheduleId'
and json_value(FileMetadata, '$[1].Value') = '82'
If the scheduleId key can appear at arbitrary positions in the array then you can restructure the query to use OPENJSON instead, e.g.:
select *
from dbo.FileSystemItems
cross apply openjson(FileMetadata) with (
[Key] nvarchar(50) N'$.Key',
Value nvarchar(50) N'$.Value'
) j
where j.[Key] = N'scheduleId'
and j.Value = N'82'

TSQL -- Extract JSON values for unknown/dynamic key in sub-object (not an array)

I'm using DataTables, DataTables Editor, JavaScript, and MSSQL 2016.
I'd like to parse this string in SQL Server:
{
"action":"edit",
"data": {
"2019-08-03":{
"Description":"sdfsafasdfasdf",
"FirstFrozenStep":"333"
}
}
}
I don't know how to access the key "2019-08-03". This represents the primary key, or the DT_RowId in DataTables Editor. It's dynamic... It could change.
Historically, I have just manipulated the data in JavaScript to a FLAT object, which is WAY easier to parse in SQL Server:
{
"action":"edit",
"DT_RowId":"2019-08-03",
"Description":"sdfsafasdfasdf",
"FirstFrozenStep":"333"
}
HOWEVER, I would like to know how to use json_query, json_value, and openjson() to drill down to the "dynamic" key mentioned above, and then access its values.
Here are all my FAILED attempts:
declare
#jsonRequest nvarchar(max) = '{"action":"edit","data":{"2019-08-03":{"Description":"sdfsafasdfasdf","FirstFrozenStep":"333"}}}'
,#json2 nvarchar(max) = '{"2019-08-03":{"Description":"sdfsafasdfasdf","FirstFrozenStep":"333"}}'
,#jsonEASY nvarchar(max) = '{"action":"edit","DT_RowId":"2019-08-03","Description":"sdfsafasdfasdf","FirstFrozenStep":"333"}'
select
json_value(#jsonRequest, '$.action') as [action]
--,json_value(#jsonRequest, '$.data.[0]') as [action]
--,json_query(#jsonRequest, '$.data[0]')
--,json_query(#jsonRequest, '$.data.[0]')
--,json_query(#jsonRequest, '$.data[0].Description')
--,json_query(#jsonRequest, '$.data.Description')
--,json_query(#jsonRequest, '$.data.[0].Description')
select
[Key]
,Value
,Type
--,json_query(value, '$')
from
openjson(#jsonRequest)
SELECT x.[Key], x.[Value]
FROM OPENJSON(#jsonRequest, '$') AS x;
select
x.[Key]
,x.[Value]
--,json_query(x.value, '$')
--,(select * from openjson(x.value))
FROM OPENJSON(#jsonRequest, '$') AS x;
SELECT x.[Key], x.[Value]
FROM OPENJSON(#json2, '$') AS x;
select
json_value(#jsonEASY, '$.action') as [action]
,json_value(#jsonEASY, '$.DT_RowId') as [DT_RowId]
,json_value(#jsonEASY, '$.Description') as [Description]
The most explicit and type-safe approach might be this:
I define your JSON with two dynamic keys
DECLARE #json NVARCHAR(MAX)=
N'{
"action":"edit",
"data": {
"2019-08-03":{
"Description":"sdfsafasdfasdf",
"FirstFrozenStep":"333"
},
"2019-08-04":{
"Description":"blah4",
"FirstFrozenStep":"444"
}
}
}';
--the query
SELECT A.[action]
,B.[key]
,C.*
FROM OPENJSON(#json) WITH([action] NVARCHAR(100)
,[data] NVARCHAR(MAX) AS JSON) A
OUTER APPLY OPENJSON(A.[data]) B
OUTER APPLY OPENJSON(B.[value]) WITH([Description] NVARCHAR(100)
,FirstFrozenStep INT) C;
The result
action key Description FirstFrozenStep
edit 2019-08-03 sdfsafasdfasdf 333
edit 2019-08-04 blah4 444
The idea in short:
The first OPENJSON() will return the two first-level-keys under the alias A. The data element is returned AS JSON, which allows to proceed with this later.
The second OPENJSON() gets A.[data] as input and is needed to get hands on the key, which is your date.
The third OPENJSON() now gets B.[value] as input.
The WITH-clause allows to read the inner elements implicitly pivoted and typed.
In general: In generic data containers it is no good idea to use descriptive parts as content. This is possible and might look clever, but it was much better to place your date as content within a date-key.
You can use OUTER APPLY to get to the next level in JSON:
SELECT L1.[key], L2.[key], L2.[value]
FROM openjson(#json,'$.data') AS L1
OUTER APPLY openjson(L1.[value]) AS L2
It will return:
key key value
2019-08-03 Description sdfsafasdfasdf
2019-08-03 FirstFrozenStep 333

Remove NULL fields from JSON in Greenplum

Using Greenplum 5.* database which is based on Postgres 8.4.
I am using row_to_json and array_to_json functions to create JSON output; but this ending up having keys with null values in JSON. Postgres latest version have json_strip_null function to remove keys with null values.
I need to import the generated JSON files to MongoDB; but mongoimport also doesn't have option to ignore null keys from JSON.
One way I tried it to create JSON file with null and then use sed to remove null fields from JSON file.
sed -i 's/\(\(,*\)"[a-z_]*[0-9]*":null\(,*\)\)*/\3/g' output.json
But looking for a way to do it database itself as it will be faster. Any suggestions how to render json_strip_null function in Greenplum without affecting the query performance?
i've had the same issue in GP 5.17 on pg8.3 - and have had success with this regex to remove the null value key-pairs. i use this in the initial insert to a json column, but you could adapt however:
select
col5,
col6,
regexp_replace(regexp_replace(
(SELECT row_to_json(j) FROM
(SELECT
col1,col2,col3,col4
) AS j)::text,
'(?!{|,)("[^"]+":null[,]*)','','g'),'(,})$','}')::json
AS nvp_json
from foo
working from the inside-out, the result of the row_to_json constructor is first cast to text, then the inner regexp replaces any "name":null, values, the outer regexp trims any hanging commas from the end, and finally the whole thing is cast back to json.
I solved this problem using plpython function. This generic function can be used to remove null and empty valued keys from any JSON.
CREATE OR REPLACE FUNCTION json_strip_null(json_with_nulls json)
RETURNS text
AS $$
import json
def clean_empty(d):
if not isinstance(d, (dict, list)):
return d
if isinstance(d, list):
return [v for v in (clean_empty(v) for v in d) if v not in (None, '')]
return {k: v for k, v in ((k, clean_empty(v)) for k, v in d.items()) if v not in (None, '')}
json_to_dict = json.loads(json_with_nulls)
json_without_nulls = clean_empty(json_to_dict)
return json.dumps(json_without_nulls, separators=(',', ':'))
$$ LANGUAGE plpythonu;
This function can be used as,
SELECT json_strip_null(row_to_json(t))
FROM table t;
You can use COALESCE to replace the nulls with an empty string or another value.
https://www.postgresql.org/docs/8.3/functions-conditional.html
The COALESCE function returns the first of its arguments that is not null. Null is returned only if all arguments are null. It is often used to substitute a default value for null values when data is retrieved for display, for example:
SELECT COALESCE(description, short_description, '(none)') ...
This returns description if it is not null, otherwise short_description if it is not null, otherwise (none).
...

How to retrieve a value in a json object in sqlite when the key is an empty string?

I am processing an sqlite table which contains json objects. These json objects have keys that are empty strings. How can I retrieve the value? For example:
select json_extract('{"foo": "bar", "":"empty"}', '$.foo') as data;
-result: "bar"
How can I retrieve "empty"?
Using your example:
sqlite> SELECT value FROM json_each('{"foo":"bar","":"empty"}') WHERE key = '';
value
----------
empty
As part of a larger query from a table:
SELECT (SELECT j.value FROM json_each(t.your_json_column) AS j WHERE j.key = '') AS data
FROM your_table AS t;