I have a JSON string as shown below. How can I create a table below or similar using SQL Server with a procedure or function? Thanks all.
I'm using SQL Server 15.0.2080.9.
{
"Person": {
"firstName": "John",
"lastName": "Smith",
"age": 25,
"Address": {
"streetAddress":"21 2nd Street",
"city":"New York",
"state":"NY",
"postalCode":"10021"
},
"PhoneNumbers": {
"home":"212 555-1234",
"fax":"646 555-4567"
}
}
}
An excellent starting point is this Q&A, but a simplified approach (if the parsed JSON has a variable structure with nested JSON objects, but without JSON arrays) is the folowing recursive statement:
JSON:
DECLARE #json nvarchar(max) = N'
{
"Person": {
"firstName": "John",
"lastName": "Smith",
"age": 25,
"Address": {
"streetAddress":"21 2nd Street",
"city":"New York",
"state":"NY",
"postalCode":"10021"
},
"PhoneNumbers": {
"home":"212 555-1234",
"fax":"646 555-4567"
}
}
}'
Statement:
;WITH rCTE AS (
SELECT
1 AS Id,
CONVERT(nvarchar(max), NULL) COLLATE DATABASE_DEFAULT AS [Parent],
CONVERT(nvarchar(max), N'Person') COLLATE DATABASE_DEFAULT AS [Key],
CONVERT(nvarchar(max), JSON_QUERY(#json, '$.Person')) COLLATE DATABASE_DEFAULT AS [Value]
UNION ALL
SELECT
r.Id + 1,
CONVERT(nvarchar(max), r.[Key]) COLLATE DATABASE_DEFAULT,
CONVERT(nvarchar(max), c.[Key]) COLLATE DATABASE_DEFAULT,
CONVERT(nvarchar(max), c.[value]) COLLATE DATABASE_DEFAULT
FROM rCTE r
CROSS APPLY OPENJSON(r.[Value]) c
WHERE ISJSON(r.[Value]) = 1
)
SELECT [Parent], [Key], [Value]
FROM rCTE
ORDER BY Id
Result:
Parent
Key
Value
Person
{"firstName": "John", "lastName": "Smith", "age": 25, "Address": {"streetAddress":"21 2nd Street", "city":"New York", "state":"NY", "postalCode":"10021"}, "PhoneNumbers": {"home":"212 555-1234", "fax":"646 555-4567" }}
Person
firstName
John
Person
lastName
Smith
Person
age
25
Person
Address
{"streetAddress":"21 2nd Street", "city":"New York", "state":"NY", "postalCode":"10021"}
Person
PhoneNumbers
{"home":"212 555-1234", "fax":"646 555-4567"}
PhoneNumbers
home
212 555-1234
PhoneNumbers
fax
646 555-4567
Address
streetAddress
21 2nd Street
Address
city
New York
Address
state
NY
Address
postalCode
10021
You can use Openjson, it would give you your desired result.
this is an example for your specific JSON:
DECLARE #Json NVARCHAR(max) = '{
"Person": {
"firstName": "John",
"lastName": "Smith",
"age": 25,
"Address": {
"streetAddress":"21 2nd Street",
"city":"New York",
"state":"NY",
"postalCode":"10021"
},
"PhoneNumbers": {
"home":"212 555-1234",
"fax":"646 555-4567"
}
}
}'
SELECT NULL AS Parent
,[KEY]
,[value]
FROM openjson(#json, '$')
UNION ALL
SELECT 'Person' AS Parent,
[KEY]
,[value]
FROM openjson(#json, '$.Person')
UNION ALL
SELECT 'Address'AS Parent,
[KEY]
,[value]
FROM openjson(#json, '$.Person.Address')
UNION ALL
SELECT 'PhoneNumbers' AS Parent ,[KEY]
,[value]
FROM openjson(#json, '$.Person.PhoneNumbers')
Related
My json format in one of the sql columns "jsoncol" in the table "jsontable" is like below.
Kindly help me to get this data using JSON_QUERY or JSON_VALUE
Please pay attention to the brackets and double quotes in the key value pairs...
{
"Company": [
{
"Info": {
"Address": "123"
},
"Name": "ABC",
"Id": 999
},
{
"Info": {
"Address": "456"
},
"Name": "XYZ",
"Id": 888
}
]
}
I am trying to retrieve all the company names using sql query. Thanks in advance
You can use:
SELECT j.name
FROM table_name t
CROSS APPLY JSON_TABLE(
t.value,
'$.Company[*]'
COLUMNS(
name VARCHAR2(200) PATH '$.Name'
)
) j
Which, for the sample data:
CREATE TABLE table_name (
value CLOB CHECK (value IS JSON)
);
INSERT INTO table_name (value)
VALUES ('{
"Company": [
{
"Info": {
"Address": "123"
},
"Name": "ABC",
"Id": 999
},
{
"Info": {
"Address": "456"
},
"Name": "XYZ",
"Id": 888
}
]
}');
Outputs:
NAME
ABC
XYZ
db<>fiddle here
You can easily use JSON_TABLE() function for this case rather provided the DB version is at least 12.1.0.2 such as
SELECT name
FROM jsontable,
JSON_TABLE(jsoncol,
'$' COLUMNS(NESTED PATH '$."Company"[*]'
COLUMNS(name VARCHAR2 PATH '$."Name"')))
Demo
I'm using MySQL 5.6.43 and trying to search through in JSON array in a table. My JSON in MySQL database is like this:
[
{
"Name": "AAA",
"CountryCode": "AFG",
"District": "Kabol",
"Population": 1780000
},
{
"Name": "BBB",
"CountryCode": "AFG",
"District": "Qandahar",
"Population": 237500
},
{
"Name": "CCC",
"CountryCode": "USD",
"District": "Qandahar",
"Population": 237500
}
]
I want to take the just AFG CountryCode's. So my result should be like this:
[
{
"Name": "AAA",
"CountryCode": "AFG",
"District": "Kabol",
"Population": 1780000
},
{
"Name": "BBB",
"CountryCode": "AFG",
"District": "Qandahar",
"Population": 237500
}
]
How can I achieve that?
SELECT test.data, JSON_ARRAYAGG(JSON_OBJECT('Name',jsontable.Name,
'CountryCode',jsontable.CountryCode,
'District',jsontable.District,
'Population',jsontable.Population)) filtered
FROM test,
JSON_TABLE(test.data,
'$[*]' COLUMNS (Name VARCHAR(255) PATH '$.Name',
CountryCode VARCHAR(255) PATH '$.CountryCode',
District VARCHAR(255) PATH '$.District',
Population VARCHAR(255) PATH '$.Population')) jsontable
WHERE jsontable.CountryCode = 'AFG'
GROUP BY test.data;
fiddle
In MySQL 5.6 you must use string functions - JSON is not implemented in this version yet:
SELECT CONCAT('[', GROUP_CONCAT('{', SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(test.data, '}', nums.num), '}', -1), '{', -1), '}'), ']') filtered
FROM test
CROSS JOIN (SELECT 1 num UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) nums
WHERE LOCATE('"CountryCode":"AFG"', SUBSTRING_INDEX(SUBSTRING_INDEX(REPLACE(test.data, ' ', ''), '}', nums.num), '}', -1))
GROUP BY test.data
fiddle
If source array may contain more than 4 objects per value then expand nums subquery.
Restriction: Neither key nor value to be searched must contain a space.
I have JSON object I need to process, using T-SQL. I can successfully retrieve all the elements, except those, having "." (dot) in their names, e.g. System.State, System.UserName. Can one advise how it can be addressed, please?
DECLARE #v_Json NVARCHAR(MAX) = N'{
"count": 56,
"value": [{
"id": 1,
"workItemId": 1234,
"fields": {
"MainValue": {"newValue": 98765},
"System.UserName": "User Name 1",
"System.Id": {
"newValue": 1234
},
"System.State": {
"newValue": "New"
}
}
},
{
"id": 2,
"workItemId": 1234,
"fields": {
"MainValue": {"newValue": 123456, "oldValue": 98765},
"System.UserName": "User Name 2",
"System.State": {
"oldValue": "new",
"newValue": "Defined"
}
}
}
]
}';
--SELECT F.[System.State]
--FROM OPENJSON (#v_Json)
-- WITH ([count] int,
-- value nvarchar(MAX) AS JSON) J
-- CROSS APPLY OPENJSON(J.value)
-- WITH ([System.State] NVARCHAR(50)) F;
SELECT JSON_VALUE(v.value, '$.id') AS id,
JSON_VALUE(v.value, '$.workItemId') AS workItemID,
JSON_VALUE(v.value, '$.fields.MainValue.newValue') AS MainValue,
JSON_VALUE(v.value, '$.fields.System.UserName') AS itemUserName,
JSON_VALUE(v.value, '$.fields.System.State') AS itemState,
JSON_VALUE(v.value, '$.fields.System.State.newValue') AS itemStateNewValue
FROM OPENJSON(#v_Json, '$.value') AS v
Edited to add a result screen, where I would expect to see, for example, "User Name 1" in column itemUserName.
It should be enough to use quotes in your JSON path:
JSON_VALUE(v.value, '$.fields."System.UserName"') AS itemUserName,
This returns with values:
DECLARE #v_Json NVARCHAR(MAX) = N'{
"count": 56,
"value": [{
"id": 1,
"workItemId": 1234,
"fields": {
"MainValue": {"newValue": 98765},
"System.UserName": "User Name 1",
"System.Id": {
"newValue": 1234
},
"System.State": {
"newValue": "New"
}
}
},
{
"id": 2,
"workItemId": 1234,
"fields": {
"MainValue": {"newValue": 123456, "oldValue": 98765},
"System.UserName": "User Name 2",
"System.State": {
"oldValue": "new",
"newValue": "Defined"
}
}
}
]
}';
--the query
SELECT JSON_VALUE(v.value, '$.id') AS id,
JSON_VALUE(v.value, '$.workItemId') AS workItemID,
JSON_VALUE(v.value, '$.fields.MainValue.newValue') AS MainValue,
JSON_VALUE(v.value, '$.fields."System.UserName"') AS itemUserName,
JSON_VALUE(v.value, '$.fields."System.State".oldValue') AS itemState,
JSON_VALUE(v.value, '$.fields."System.State".newValue') AS itemStateNewValue
FROM OPENJSON(#v_Json, '$.value') AS v;
To repeat my answer from SQL Server Central, with the 3rd set of sample data I was provided (the above is the 4th..):
DECLARE #v_Json NVARCHAR(MAX) = N'{
"count": 56,
"value": [{
"id": 1,
"workItemId": 1234,
"fields": {
"System.Id": {
"newValue": 1234
},
"System.State": {
"newValue": "New"
}
}
},
{
"id": 2,
"workItemId": 1234,
"fields": {
"System.State": {
"oldValue": "new",
"newValue": "Defined"
}
}
}
]
}';
SELECT F.[System.State]
FROM OPENJSON (#v_Json,'$.value')
WITH (fields nvarchar(MAX) AS JSON ) J
CROSS APPLY OPENJSON(J.fields)
WITH ([System.State] nvarchar(MAX) AS JSON) F;
Which returns the dataset below:
System.State
-----------------------------------------
{
"newValue": "New"
}
{
"oldValue": "new",
"newValue": "Defined"
}
db<>fiddle
This opens and flattens the JSON and assigns unique column names
select *
from openjson (#v_Json) with ([count] int,
[value] nvarchar(MAX) AS JSON) J
cross apply openjson(j.[value])
with (id int,
workItemId int,
fields nvarchar(max) as json) v
cross apply openjson(v.fields) with ([System.Id] nvarchar(max) as json,
[System.State] nvarchar(max) as json) f
outer apply openjson(f.[System.Id]) with (sys_id_newValue int '$.newValue',
sys_id_oldValue int '$.oldValue') si
outer apply openjson(f.[System.State]) with (sys_st_newValue nvarchar(4000) '$.newValue',
sys_st_oldValue nvarchar(4000) '$.oldValue');
I have below JSON. I was trying to construct a query to fetch the FirstName, LastName, Iphone Number and Home Number. I am trying to use JSON Path filter expression. Its not working for me.
{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"address" : {
"streetAddress": "naist street",
"city" : "Nara",
"postalCode" : "630-0192"
},
"phoneNumbers": [
{
"type" : "iPhone",
"number": "0123-4567-8888"
},
{
"type" : "home",
"number": "0123-4567-8910"
}
]
}
Query used
DECLARE #jsonInfo NVARCHAR(MAX)
SET #jsonInfo=N'{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"address" : {
"streetAddress": "naist street",
"city" : "Nara",
"postalCode" : "630-0192"
},
"phoneNumbers": [
{
"type" : "iPhone",
"number": "0123-4567-8888"
},
{
"type" : "home",
"number": "0123-4567-8910"
}
]
}'
SELECT
JSON_VALUE(#jsonInfo,'$.firstName') AS FirstName,
JSON_VALUE(#jsonInfo,'$.lastName') AS LastName
--JSON_VALUE(#jsonInfo,'$.phoneNumbers[?(#.type=="iPhone")].number') AS IPhoneNumber,
--JSON_VALUE(#jsonInfo,'$.phoneNumbers[?(#.type=="home")].number') AS HomeNumber
Regards
Amirtharaj
One way to parse this JSON is with OPENJSON() and explicit schema. phoneNumbers is a JSON array, so you need an additional OPENSJON() call.
SELECT
j1.firtstName, j1.lastName, j1.streetAddress, j1.city, j1.postalCode,
j2.*
FROM OPENJSON(#jsonInfo) WITH (
firtstName varchar(100) '$.firstName',
lastName varchar(100) '$.lastName',
streetAddress varchar(100) '$.address.streetAddress',
city varchar(100) '$.address.city',
postalCode varchar(100) '$.address.postalCode',
phoneNumbers nvarchar(max) '$.phoneNumbers' AS JSON
) j1
CROSS APPLY (
SELECT
MAX(CASE WHEN [type] = 'iPhone' THEN [number] END) AS iPhone,
MAX(CASE WHEN [type] = 'home' THEN [number] END) AS home
FROM OPENJSON(j1.phoneNumbers) WITH (
type varchar(10) '$.type',
number varchar(20) '$.number'
)
) j2
Result:
firtstName lastName streetAddress city postalCode iPhone ome
John doe naist street Nara 630-0192 0123-4567-8888 0123-4567-8910
Of course, you can extract each phone number from $.phoneNumbers JSON array using $.phoneNumbers[x].number as path expression (x is zero-based index):
SELECT
j1.firtstName, j1.lastName, j1.streetAddress, j1.city, j1.postalCode,
j1.number1, j1.number2
FROM OPENJSON(#jsonInfo) WITH (
firtstName varchar(100) '$.firstName',
lastName varchar(100) '$.lastName',
streetAddress varchar(100) '$.address.streetAddress',
city varchar(100) '$.address.city',
postalCode varchar(100) '$.address.postalCode',
number1 varchar(100) '$.phoneNumbers[0].number',
number2 varchar(100) '$.phoneNumbers[1].number'
) j1
I want to display the parameter ST and NextTime from table #json. The parameters id and Timestamp appear normally. I try the following but does not show any effect.Any possible answers?
My Json
{
"PCol": [{
"Id": 15,
"TimeStamp": "2018-02-1",
"Val": {
"States": [{
"Numbers": {
"Number": [5, 8]
},
"CS": {
"ST": "25"
},
"Changes": [{
"NextTime": 1
}]
}]
}
}]
}
My Sql Query
SELECT * FROM OPENJSON((select * from #json),N'$.PCol')
WITH (
[Id] INT N'$.Id ',
[TimeStamp] NVARCHAR(MAX) N'$.TimeStamp',
**[ST] INT N'$.Val.States.CS.ST'**
)
Thanks
Not going to lie, my OPENJSON knowledge is poor (so this might be able to be more succinct), however, this works:
DECLARE #JSON nvarchar(MAX) =
N' {
"PCol": [{
"Id": 15,
"TimeStamp": "2018-02-1",
"Val": {
"States": [{
"Numbers": {
"Number": [5, 8]
},
"CS": {
"ST": "25"
}
}]
}
}]
} ';
SELECT P.Id,
P.TimeStamp,
V.ST
FROM OPENJSON(#JSON,N'$.PCol') WITH ([Id] INT N'$.Id ',
[TimeStamp] NVARCHAR(MAX) N'$.TimeStamp',
[Vals] nvarchar(MAX) N'$.Val' AS JSON) P
CROSS APPLY OPENJSON(P.Vals,N'$.States') WITH (ST int N'$.CS.ST') V
For the latest JSON, this works:
SELECT P.Id,
P.TimeStamp,
V.ST,
C.NextTime
FROM OPENJSON(#JSON,N'$.PCol') WITH ([Id] INT N'$.Id ',
[TimeStamp] NVARCHAR(MAX) N'$.TimeStamp',
[Vals] nvarchar(MAX) N'$.Val' AS JSON) P
CROSS APPLY OPENJSON(P.Vals,N'$.States') WITH (ST int N'$.CS.ST',
[Changes] nvarchar(MAX) N'$.Changes' AS JSON) V
CROSS APPLY OPENJSON(V.[Changes]) WITH (NextTime int '$.NextTime') C