Return string in a array without object - sql

This is how I am getting:
"skills":[
{
"cityname":"Kaduna North"
}
]
How I want is:
"skills":["Kaduna North"]
is that possible?

Try the below:
DECLARE #jsonInfo NVARCHAR(MAX)
SET #jsonInfo=N'{
"skills": [{
"cityname": "Kaduna North"
}]
}'
;
SELECT
concat('"skills":["',
JSON_VALUE(#jsonInfo,'$.skills[0].cityname')
,'"]'
)
;
Or use the below:
SELECT
JSON_QUERY(
concat('["',
JSON_VALUE(#jsonInfo,'$.skills[0].cityname')
,'"]'
) ) as skills
FOR JSON PATH

Related

How to flatten nested array from JSON in SQL Server

I am trying to flatten nested array from JSON in SQL Server, using the code below, but without success.
Used JSON
'{
"shipmentDetails": {
"shipmentId": "JHVJD5627278788"
},
"shipmentStops": [
{
"stopSequence": 1,
"orderReferenceNumbers": [
"2120549020", "test"
]
},
{
"stopSequence": 2,
"orderReferenceNumbers": [
"2120549020", "2120549002"
]
}
]
}'
DECLARE #Step AS NVARCHAR(max) = N'Variables declaration';
DECLARE #JSON1 AS NVARCHAR(MAX);
SET #JSON1 = '{
"shipmentDetails": {
"shipmentId": "JHVJD5627278788"
},
"shipmentStops": [
{
"stopSequence": 1,
"orderReferenceNumbers": [
"2120549020", "test"
]
},
{
"stopSequence": 2,
"orderReferenceNumbers": [
"2120549020", "2120549002"
]
}
]
}'
IF OBJECT_ID('JSONPO2') IS NOT NULL
DROP TABLE JSONPO2
SET #Step = N'JSON data parsing and loading into JSONPO2 temp table'
SELECT DISTINCT ShipDetails.shipmentId AS shipmentId
,ShipmentStops.stopSequence AS stopSequence
,ShipmentStops.orderReferenceNumbers AS orderReferenceNumbers
INTO JSONPO2
FROM OPENJSON(#JSON1) WITH (
shipmentDetails NVARCHAR(MAX) AS JSON
,shipmentStops NVARCHAR(MAX) AS JSON
) AS [Data]
CROSS APPLY OPENJSON(shipmentDetails) WITH (shipmentId NVARCHAR(20)) AS ShipDetails
CROSS APPLY OPENJSON(shipmentStops) WITH (
stopSequence INT
,orderReferenceNumbers NVARCHAR(MAX) AS JSON
) AS ShipmentStops
CROSS APPLY OPENJSON(orderReferenceNumbers) WITH (orderReferenceNumbers VARCHAR(max))
AS orderReferenceNumbers
SELECT *
FROM JSONPO2
From the above code, I receive only two rows with a strange array
shipmentId
stopSequence
orderReferenceNumbers
JHVJD5627278788
1
[ "2120549020", "test" ]
JHVJD5627278788
2
[ "2120549020", "2120549002" ]
How to change the code to parse nested arrays and have four rows like below?
shipmentId
stopSequence
orderReferenceNumbers
JHVJD5627278788
1
2120549020
JHVJD5627278788
1
test
JHVJD5627278788
2
2120549020
JHVJD5627278788
2
2120549002
Appreciate any help :)
Your issue is when trying to expand the array using the WITH clause:
CROSS APPLY OPENJSON(orderReferenceNumbers)
WITH (orderReferenceNumbers VARCHAR(max)) AS orderReferenceNumbers
The JSON you are opening though has no property "orderReferenceNumbers", it is simply:
["2120549020", "test"]
So this is returning NULL. You'd see this in your select if you were selecting orderReferenceNumbers.orderReferenceNumbers rather than ShipmentStops.orderReferenceNumbers.
You don't need to use WITH if you are opening a simple JSON array of primitive types. The following query will return the output you are after:
DECLARE #JSON1 AS NVARCHAR(MAX) = N'{
"shipmentDetails": {
"shipmentId": "JHVJD5627278788"
},
"shipmentStops": [
{
"stopSequence": 1,
"orderReferenceNumbers": [
"2120549020", "test"
]
},
{
"stopSequence": 2,
"orderReferenceNumbers": [
"2120549020", "2120549002"
]
}
]
}';
SELECT sd.shipmentId,
ss.stopSequence,
orderReferenceNumber = orn.Value
FROM OPENJSON(#JSON1)
WITH(shipmentDetails NVARCHAR(MAX) AS JSON, shipmentStops NVARCHAR(MAX) AS JSON) AS d
CROSS APPLY OPENJSON(d.shipmentDetails)
WITH(shipmentId NVARCHAR(20)) AS sd
CROSS APPLY OPENJSON(d.shipmentStops)
WITH(stopSequence INT, orderReferenceNumbers NVARCHAR(MAX) AS JSON) AS ss
CROSS APPLY OPENJSON(orderReferenceNumbers) AS orn;
Example on db<>fiddle
As an aside, if you will only ever have one shipmentId in the JSON (which would make sense otherwise you'd end up with cross joins) you can simplify this slightly, and remove one of the OPENJSON()s:
SELECT d.shipmentId,
ss.stopSequence,
orderReferenceNumber = orn.Value
FROM OPENJSON(#JSON1)
WITH(ShipmentId NVARCHAR(20) '$.shipmentDetails.shipmentId',
shipmentStops NVARCHAR(MAX) AS JSON) AS d
CROSS APPLY OPENJSON(d.shipmentStops)
WITH(stopSequence INT, orderReferenceNumbers NVARCHAR(MAX) AS JSON) AS ss
CROSS APPLY OPENJSON(ss.orderReferenceNumbers) AS orn;

Using JSON_VALUE for parse column in SQL Server table

I have never worked with JSON in SQL Server before that's why need some help.
I have written a simple snippet of code:
DECLARE #json NVARCHAR(4000)
SET #json =
N'{
"id":"40476",
"tags":[
{
"id":"5f5883",
},
{
"id":"5fc8",
}
],
"type":"student",
"external_id":"40614476"
}'
SELECT
JSON_value(#json, '$.tags[0].id') as tags
In sample above I write code how get first "id" from "tags".
But how looks like script if in "tags" not 2 "id", but an unknown number this "id" and result should be in column like this:
1 5f5883
2 5fc8
You may use OPENJSON() with explicit schema to parse the $.tags JSON array:
DECLARE #json NVARCHAR(4000)
SET #json =
N'{
"id":"40476",
"tags":[
{
"id":"5f5883"
},
{
"id":"5fc8"
}
],
"type":"student",
"external_id":"40614476"
}'
SELECT id
FROM OPENJSON(#json, '$.tags') WITH (id varchar(10) '$.id')
Result:
id
------
5f5883
5fc8
If you want to get the index of each id in the $.tags JSON array, then you need a combination of OPENJSON() with default schema and JSON_VALUE():
SELECT CONVERT(int, [key]) AS rn, JSON_VALUE([value], '$.id') AS id
FROM OPENJSON(#json, '$.tags')
Result:
rn id
----------
0 5f5883
1 5fc8

How to PARSE_JSON from Snowflake Field?

I have a table that looks like:
ID|FIELD1
1|[ { "list": [ {} ] } ]
2|[ { "list": [ { "item": "" } ] } ]
3|[ { "list": [ { "item": "Tag1" }, { "item": "Tag2" } ] } ]
And I want to get all the tags associated to this specific query such that I can just get a list:
Tag1,Tag2
I've tried
SELECT PARSE_JSON(FIELD1[0]['list'][0]['item']) FROM MY_TABLE
WHERE PARSE_JSON(FIELD1[0]['list'][0]) != '{}'
But I get
JSON: garbage in the numeric literal: 65-310 , pos 7
How can I properly unpack these values in SQL?
UPDATE: Clumsy Solution
SELECT LISTAGG(CODES,'\',\'') AS PROMO_CODES
FROM
(SELECT DISTINCT FIELD1[0]['list'][0]['item'] AS CODES FROM MY_TABLE
WHERE FIELD1[0]['list'][0] IS NOT NULL
AND FIELD1[0]['list'][0] != '{}'
AND FIELD1[0]['list'][0]['item'] != ''
)
Please have a look into below knowledge article, if this helps in your case:
https://community.snowflake.com/s/article/Dynamically-extracting-JSON-using-LATERAL-FLATTEN
As I see, the Clumsy Solution does not provide the correct result. It shows only Tag1. So here's my solution:
select LISTAGG( v.VALUE:item, ',' ) from MY_TABLE,
lateral flatten (parse_json(FIELD1[0]):list) v
WHERE v.VALUE:item <> '';
I would recommend to add DISTINCT to prevent duplicate tags in the output:
select LISTAGG( DISTINCT v.VALUE:item, ',' ) from MY_TABLE,
lateral flatten (parse_json(FIELD1[0]):list) v
WHERE v.VALUE:item <> '';
If there are more items in the FIELD1 array (ie 0,1,2), you may use this one:
select LISTAGG( DISTINCT v.VALUE:item, ',' ) from MY_TABLE,
lateral flatten(FIELD1) f,
lateral flatten (parse_json(f.VALUE):list) v
WHERE v.VALUE:item <> '';

How to Set OPENJSON Path to Nested Array

I'm trying to set the path for my OPENJSON function for the nested array, but it's not working. Tried different variations and examples/resources I found online and still cannot figure it out.
Any ideas?
EDIT:
To be clear, I know how to do this with CROSSAPPLY and other methods. My question is in regards on how to do this specifically with the OPENJSON function's path parameter if possible.
Here's my code:
DECLARE #json NVARCHAR(MAX);
SET #json = '
{
"orders": [
{
"id":"1",
"date":"7/4/2020",
"orderlines": [
{"id": "1", "amount": 100},
{"id": "2", "amount": 200}
]
},
{
"id":"2",
"date":"7/4/2020",
"orderlines": [
{"id": "3", "amount": 300},
{"id": "4", "amount": 400}
]
}
]
}
'
-- None of these return results. How do I specify the path to the "orderlines" array?
SELECT * FROM OPENJSON(#json,'$.orderlines');
SELECT * FROM OPENJSON(#json,'$.orderlines[1]');
SELECT * FROM OPENJSON(#json,'$.orders.orderlines');
SELECT * FROM OPENJSON(#json,'$.orders.orderlines[1]');
-- This works:
SELECT * FROM OPENJSON(#json,'$.orders');
You can use WITH and put a name on inside values and use CROSS APPLY to use them in another OPENJSON. Now you can have all inside objects together.
SELECT orderlines.id, orderlines.amount
FROM OPENJSON(#json, '$.orders') WITH (orderlines NVARCHAR(MAX) '$.orderlines' AS JSON) orders
CROSS APPLY OPENJSON(orders.orderlines) WITH (id INT '$.id', amount INT '$.amount') orderlines
Learn more here.
Also if need to get specific item in array:
SELECT * FROM OPENJSON(#json, '$.orders[0].orderlines[0]')
-- OR
SELECT JSON_VALUE(#json, '$.orders[0].orderlines[0].amount')
To make it clear for others who may be viewing this, the part of Iman Kazemi's response that was the answer was the following of what he wrote:
SELECT * FROM OPENJSON(#json, '$.orders[0].orderlines[0]')
I neglected to specify the index on the order's array.
Thanks again to Iman.
You can try the following:
SELECT *
FROM OPENJSON (#json, '$.orders')
WITH (
id INT '$.id',
[date] VARCHAR(10) '$.date',
orderlines_id1 INT '$.orderlines[0].id',
orderlines_amount1 MONEY '$.orderlines[0].amount',
orderlines_id2 INT '$.orderlines[1].id',
orderlines_amount2 MONEY '$.orderlines[1].amount'
) AS Orders
Please see the db<>fiddle here.

JSON to SQL - Extracting from JSON Array?

I have an exercise to extract some data from a larger JSON object however the data is added as multiple objects or perhaps an array of sorts.
An example below;
DECLARE #json NVARCHAR(MAX) = '{
"N.data.-ce731645-e4ef-4784-bc02-bb90b4c9e9e6": "Some Data",
"N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f": [
{
"date_1": "2018-10-20T23:00:00.000Z"
},
{
"date_1": "2018-10-21T23:00:00.000Z"
}
]
}'
I need to extract these datetime entries from the "date_1" identifier into ideally a CSV list. From that I can do my own manipulations.
2018-10-20T23:00:00.000Z, 2018-10-21T23:00:00.000Z
I am familiar with JSON_VALUE() however not with its use outside of a simple piece of one dimensional data.
What I have so far;
DECLARE #json NVARCHAR(MAX) = '{
"N.data.-ce731645-e4ef-4784-bc02-bb90b4c9e9e6": "Some Data",
"N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f": [
{
"date_1": "2018-10-20T23:00:00.000Z"
},
{
"date_1": "2018-10-21T23:00:00.000Z"
}
]
}'
SELECT value FROM OPENJSON(#json)
Is there a way to achive the expected output outside of complex substring() and replace() uses?
Using SQL Server 2017
Microsoft SQL Server 2017 (RTM) - 14.0.1000.169 (X64) Aug 22 2017 17:04:49 Copyright (C) 2017 Microsoft Corporation Express Edition (64-bit) on Windows Server 2012 R2 Datacenter 6.3 <X64> (Build 9600: ) (Hypervisor)
Thanks
Since SQL Server 2017, the extraction can be done via native OPENJSON:
DECLARE #json NVARCHAR(MAX) = '{
"N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f": [
{
"date_1": "2018-10-20T23:00:00.000Z"
},
{
"date_1": "2018-10-21T23:00:00.000Z"
}
]
}'
SELECT
JSON_VALUE(child_value.value, '$.date_1') AS [key]
FROM OPENJSON(#json, '$') AS nda
cross apply openjson(nda.value, '$') as child_value
Results to:
key
2018-10-20T23:00:00.000Z
2018-10-21T23:00:00.000Z
Is there a way to adjust this to extract the values for a specific
key, "N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f" in the
example
In this case, that query can be slightly simplified to:
DECLARE #id nvarchar(200) = 'N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f'
SELECT
JSON_VALUE(nda.value, '$.date_1') AS [key]
FROM OPENJSON(#json, concat('$."',#id,'"')) AS nda
or without parametrization:
SELECT
JSON_VALUE(nda.value, '$.date_1') AS [key]
FROM OPENJSON(#json, '$."N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f"') AS nda
Use a cross apply with OPENJSON() using a with_clause:
DECLARE #json NVARCHAR(MAX) = '{
"N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f": [
{
"date_1": "2018-10-20T23:00:00.000Z"
},
{
"date_1": "2018-10-21T23:00:00.000Z"
}
]
}';
SELECT [b].*
FROM OPENJSON(#json) [a]
CROSS APPLY
OPENJSON([a].[Value])
WITH (
[date_1] DATETIME '$.date_1'
) [b];
Another possible approach, using OPENJSON(). With this approach you can get key/value pairs from your nested JSON array, even if this array has different key names.
DECLARE #json nvarchar(max)
SET #json =
N'{"N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f": [
{
"date_1": "2018-10-20T23:00:00.000Z"
},
{
"date_1": "2018-10-21T23:00:00.000Z"
},
{
"date_2": "2019-10-21T23:00:00.000Z"
}
]
}'
SELECT
x.[key] AS SessionData,
z.[key],
z.[value]
FROM OPENJSON(#json) x
CROSS APPLY (SELECT * FROM OPENJSON(x.[value])) y
CROSS APPLY (SELECT * FROM OPENJSON(y.[value])) z
--WHERE z.[key] = 'date_1'
Output:
SessionData key value
N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f date_1 2018-10-20T23:00:00.000Z
N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f date_1 2018-10-21T23:00:00.000Z
N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f date_2 2019-10-21T23:00:00.000Z
Update:
If you want to filter by key name, next may help:
DECLARE #json NVARCHAR(MAX) = '{
"N.data.-ce731645-e4ef-4784-bc02-bb90b4c9e9e6": "Some Data",
"N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f": [
{
"date_1": "2018-10-20T23:00:00.000Z"
},
{
"date_1": "2018-10-21T23:00:00.000Z"
}
]
}'
SELECT z.[value]
--SELECT STRING_AGG(z.[value], ', ') [Data] -- with string aggregation
FROM OPENJSON(#json) x
CROSS APPLY (SELECT * FROM OPENJSON(x.[value])) y
CROSS APPLY (SELECT * FROM OPENJSON(y.[value])) z
WHERE x.[key] = 'N.data.sessionDates-7f1790d3-9175-43aa-962b-161ee3b8615f'
Output:
value
2018-10-20T23:00:00.000Z
2018-10-21T23:00:00.000Z
-- With string aggregation
--Data
--2018-10-20T23:00:00.000Z, 2018-10-21T23:00:00.000Z