Is there a way to parameterize the second argument of openjson - sql

My json data looks like:
SET #json='{
"_id": "4erutit8979044kd5",
"ADDRESSES": {
"1": {
"VALIDATED": "",
"TYPE": "billing",
"RESIDENTIAL": "",
"REGION": "ON",
"POSTAL": "L6789W",
"PO": 0,
"PHONE": "222222",
"NAME_2": "Kapil",
"NAME_1": "Kaushal",
"LINE_2": "",
"LINE_1": "215 Wards Ct.",
"EMAIL": "kapilk#gmail.com",
"COUNTRY": "IN",
"CITY": "Jodhpur",
"LAST_USED": 1435590000.0
},
"2": {
"TYPE": "billing",
"RESIDENTIAL": "",
"REGION": "JD",
"POSTAL": "2222",
"PO": 0,
"PHONE": "",
"NAME_2": "Salman",
"NAME_1": "Kursheed",
"LINE_2": "",
"LINE_1": "1459 Thomas Street",
"EMAIL": "salmank#gmail.com",
"COUNTRY": "IN",
"CITY": "Jodhpur",
"LAST_USED": 1436460000.0,
"VALIDATED": "dirty"
},
"3": {
"VALIDATED": "clean",
"TYPE": "shipping",
"CITY": "Jaisalmer",
"COUNTRY": "IN",
"EMAIL": "rajk#gmail.com",
"LINE_1": "1020 Carripa Enclave",
"LINE_2": "",
"NAME_1": "Raj",
"NAME_2": "Kumar",
"PO": 0,
"POSTAL": "222234",
"REGION": "JS",
"LAST_VALIDATED": "2015-07-14T16:20:42.242Z",
"LAST_USED": 1436460000.0
}
}, ...
and so on
I want to achieve something like:
WHILE #cnt < 3
BEGIN
--insert into dummy_table
select *
from openjson (#json,'$.ADDRESSES."#cnt"')
SET #cnt = #cnt + 1;
END;
The line is working fine as:
select * from openjson (#json,'$.ADDRESSES."1"')
select * from openjson (#json,'$.ADDRESSES."1"')
But not with a variable #cnt, even if i define #cnt as char = '1'.
Please help me achieve the same. The no of addresses may differ, so i want to make it dynamic.

The exact answer is Yes, but it depends on the SQL Server version. You have the follolwing options:
For SQL Server 2017+, you can provide a variable as the value of path. Note that, when the key name starts with a dollar sign or contains special characters such as spaces or numbers, you need to surround it with quotes.
DECLARE #cnt int
SET #cnt = 1
--INSERT INTO dummy_table
SELECT *
FROM OPENJSON(#json, CONCAT('$.ADDRESSES."', #cnt, '"'))
For SQL Server 2016+ you need to parse the input JSON with OPENJSON() and a default schema. The result is a table with columns key, value and type.
DECLARE #cnt int
SET #cnt = 1
--INSERT INTO dummy_table
SELECT j2.*
FROM OPENJSON(#json, '$.ADDRESSES') j1
CROSS APPLY OPENJSON(j1.[value]) j2
WHERE j1.[key] = #cnt
Result:
key value type
VALIDATED 1
TYPE billing 1
RESIDENTIAL 1
REGION ON 1
POSTAL L6789W 1
PO 0 2
PHONE 222222 1
NAME_2 Kapil 1
NAME_1 Kaushal 1
LINE_2 1
LINE_1 215 Wards Ct. 1
EMAIL kapilk#gmail.com 1
COUNTRY IN 1
CITY Jodhpur 1
LAST_USED 1435590000.0 2
As an additional option, you don't need a WHILE loop to get specific values from the input JSON. The following statement parses the values from $.ADDRESSES.1, $.ADDRESSES.2 and $.ADDRESSES.3 keys.
--INSERT INTO dummy_table
SELECT j2.*
FROM (VALUES (1), (2), (3)) v(cnt)
JOIN OPENJSON(#json, '$.ADDRESSES') j1 ON CONVERT(int, j1.[key]) = v.cnt
CROSS APPLY OPENJSON(j1.[value]) j2

Try this:
DECLARE #json NVARCHAR(MAX);
SET #json='{
"_id": "4erutit8979044kd5",
"ADDRESSES": {
"1": {
"VALIDATED": "",
"TYPE": "billing",
"RESIDENTIAL": "",
"REGION": "ON",
"POSTAL": "L6789W",
"PO": 0,
"PHONE": "222222",
"NAME_2": "Kapil",
"NAME_1": "Kaushal",
"LINE_2": "",
"LINE_1": "215 Wards Ct.",
"EMAIL": "kapilk#gmail.com",
"COUNTRY": "IN",
"CITY": "Jodhpur",
"LAST_USED": 1435590000.0
},
"2": {
"TYPE": "billing",
"RESIDENTIAL": "",
"REGION": "JD",
"POSTAL": "2222",
"PO": 0,
"PHONE": "",
"NAME_2": "Salman",
"NAME_1": "Kursheed",
"LINE_2": "",
"LINE_1": "1459 Thomas Street",
"EMAIL": "salmank#gmail.com",
"COUNTRY": "IN",
"CITY": "Jodhpur",
"LAST_USED": 1436460000.0,
"VALIDATED": "dirty"
},
"3": {
"VALIDATED": "clean",
"TYPE": "shipping",
"CITY": "Jaisalmer",
"COUNTRY": "IN",
"EMAIL": "rajk#gmail.com",
"LINE_1": "1020 Carripa Enclave",
"LINE_2": "",
"NAME_1": "Raj",
"NAME_2": "Kumar",
"PO": 0,
"POSTAL": "222234",
"REGION": "JS",
"LAST_VALIDATED": "2015-07-14T16:20:42.242Z",
"LAST_USED": 1436460000.0
}
}'
DECLARE #cnt INT = 1;
DECLARE #query NVARCHAR(128);
WHILE #cnt <= 3
BEGIN
--insert into dummy_table
SET #query = '$.ADDRESSES."' + CAST(#cnt AS VARCHAR(4)) + '"'
select *
from openjson (#json,#query)
SET #cnt = #cnt + 1;
END;
Just build the second parameter as a string and pass it.

Related

Select data from Json array MS SQL Server

I have to select data from Json like this:
[
{
"id": 10100,
"externalId": "100000035",
"name": "Test1",
"companyId": 10099,
"phone": "0738003811",
"email": "test#Test.com",
"mainAddress": {
"county": "UK",
"province": "test",
"zipCode": "01234",
"city": "test",
"street": "test",
"gln": "44,37489331;26,21941193",
"country": {
"iso2": "UK",
"iso3": "UK"
}
},
"active": false,
"main": true,
"stores": [
"Test"
],
"attributes": [
{
"attributeId": 1059,
"attributeName": "CH6 name",
"attributeExternalId": null,
"attributeValueId": 74292,
"attributeValueType": "MONO_LINGUAL",
"attributeValueEid": null,
"attributePlainValue": "Unknown"
},
{
"attributeId": 1061,
"attributeName": "BD",
"attributeExternalId": null,
"attributeValueId": 81720,
"attributeValueType": "MONO_LINGUAL",
"attributeValueEid": null,
"attributePlainValue": "Not assigned"
}
],
"daysSinceLastOrder": null
},
{
"id": 62606,
"externalId": "VL_LC_000190",
"name": "Test",
"companyId": 17793,
"phone": "44333424",
"email": "test#email.com",
"mainAddress": {
"firmName": "test",
"county": "test",
"province": "test",
"zipCode": "247555",
"city": "test",
"street": "test",
"gln": "44.8773851;23.9223518",
"country": {
"iso2": "RO",
"iso3": "ROU"
},
"phone": "07547063789"
},
"active": true,
"main": false,
"stores": [
"Valcea"
],
"attributes": [
{
"attributeId": 1042,
"attributeName": "Type of location",
"attributeExternalId": "TYPE_OF_DIVISION",
"attributeValueId": 34506,
"attributeValueType": "MONO_LINGUAL",
"attributeValueEid": "Small OTC (<40mp)",
"attributePlainValue": "Small OTC (<40mp)"
},
{
"attributeId": 17,
"attributeName": "Limit for payment",
"attributeExternalId": "LIMIT_FOR_PAYMENT_IN_DAYS",
"attributeValueId": 59120,
"attributeValueType": "NUMBER",
"attributeValueEid": null,
"attributePlainValue": "28"
}
],
"daysSinceLastOrder": 147
}
]
I know how to select data from simple json object using "FROM OPENJSON",
but now I have to select a
AttributeValueId, AttributeId and AttributeName, attributePlainValue and CompanyId for each Attribute. So I dont know how to select data from attributes array and then how to join to this CompanyId which is one level up.
Maybe someone knows how write this query.
As mentioned by #lptr in the comments:
You need to pass the result of one OPENJSON to another, using CROSS APPLY. You can select a whole JSON object or array as a property, by using the syntax AS JSON
select
t1.companyid,
t2.*
from openjson(#j)
with (
companyId int,
attributes nvarchar(max) as json
) as t1
cross apply openjson(t1.attributes)
with
(
attributeId int,
attributeName nvarchar(100),
attributeValueId nvarchar(100),
attributePlainValue nvarchar(100)
) as t2;
db<>fiddle
For example, you can use code like this.
f1.metaData->"$.identity.customerID" = '.$customerID.'

Extract text from JSON in SQL Server

I am trying to extract a specific value from a JSON column in SQL Server. Unfortunately I have read several posts on this topic but still cannot figure out how to translate their solutions to what I need. I am looking to extract "foo testing" but simply do not understand how to get at this with a nested JSON. Can someone please advise?
The structure of the JSON column is:
{
"values": [
{
"id": "x01",
"status": "STATUS1",
"subStatus": "SubStatus1",
"values": [
{
"key": "dropdown",
"value": "",
"optionType": null
}
]
},
...
{
"id": "x03",
"status": "STATUS3",
"subStatus": "SubStatus3",
"values": [
{
"key": "dropdown",
"value": "",
"optionType": null
},
{
"key": "textInput",
"value": null,
"optionType": null
},
{
"key": "checkbox1",
"value": true,
"optionType": null
},
{
"key": "textInput2",
"value": "foo testing",
"optionType": null
}
]
}
]
}
The statement depends on the structure of the parsed JSON, in your case you need to use two nested OPENJSON() calls and additinal APPLY operators. Note, that you need to use AS JSON in a "values" column definition to specify that the referenced property contains an inner JSON array and the type of that column must be nvarchar(max).
Test table:
DECLARE #json varchar(max) = '
{
"values": [
{
"id": "x01",
"status": "STATUS1",
"subStatus": "SubStatus1",
"values": [
{"key": "dropdown", "value": "", "optionType": null}
]
},
{
"id": "x03",
"status": "STATUS3",
"subStatus": "SubStatus3",
"values": [
{"key": "dropdown", "value": "", "optionType": null},
{"key": "textInput", "value": null, "optionType": null},
{"key": "checkbox1", "value": true, "optionType": null},
{"key": "textInput2", "value": "foo testing", "optionType": null}
]
}
]
}
'
SELECT JsonColumn
INTO JsonTable
FROM (VALUES (#json)) v (JsonColumn)
Statement:
SELECT j1.[id], j2.[key], j2.[value] -- or add all columns
FROM JsonTable t
CROSS APPLY OPENJSON(t.JsonColumn, '$.values') WITH (
[id] varchar(3) '$.id',
[status] varchar(30) '$.status',
[subStatus] varchar(30) '$.subStatus',
[values] nvarchar(max) '$.values' AS JSON
) j1
CROSS APPLY OPENJSON(j1.[values], '$') WITH (
[key] varchar(50) '$.key',
[value] varchar(50) '$.value',
[optionType] varchar(50) '$.optionType'
) j2
Result:
id key value
---------------------------
x01 dropdown
x03 dropdown
x03 textInput
x03 checkbox1 true
x03 textInput2 foo testing
you can use following query
;with summery as(
SELECT *
FROM OPENJSON((SELECT value FROM OPENJSON(#json)))
WITH (
id NVARCHAR(50) 'strict $.id',
status NVARCHAR(50) '$.status',
subStatus NVARCHAR(50) '$.subStatus',
[values] NVARCHAR(max) '$.values' AS JSON
)
)
select id,status,subStatus,[key],value,optionType from summery
CROSS APPLY OPENJSON(summery.[values])
WITH (
[key] NVARCHAR(50) '$.key',
[value] NVARCHAR(50) '$.value',
[optionType] NVARCHAR(50) '$.optionType'
);
demo in db<>fiddle

How to get data from json column in mssql

I'm struggling to write a query that gets value from json column with some specific conditions. I have a table named Table1 with a column of type nvarchar(max) named Data that contains some json values. The json itself looks like this:
{
"Addresses": [
{
"ApartmentNumber": "1",
"City": "Rome",
"CountryCode": "IT",
"HouseNumber": "2",
"Post": "Rome",
"PostalCode": "11-111",
"Region": "Rome",
"Street": "Italian",
"StreetPrefix": "St.",
"TypeCode": "PERMANENT"
},
{
"ApartmentNumber": "11",
"City": "Madrid",
"CountryCode": "ES",
"HouseNumber": "22",
"Post": "Madrid",
"PostalCode": "11-111",
"Region": "Madrid",
"Street": "Spanish",
"StreetPrefix": "St.",
"TypeCode": "CORRESPONDENCE"
}
],
"Contacts": [
{
"TypeCode": "EMAIL",
"DefaultContact": false,
"Value": "sample#xyz.com"
}
],
"PersonData": {
"BirthDate": "1968-08-03T00:00:00",
"CitizenshipCode": "US",
"DeathDate": "0001-01-01T00:00:00",
"FirstName": "John",
"Gender": "M",
"LastName": "Jones"
}
}
I would like to get a value of CountryCode from the Addresses node where TypeCode is "CORRESPONDENCE". I tried to achieve that with combinations of JSON_VALUE and JSON_QUERY functions but I failed. Below are some examples of my trials:
query:
SELECT JSON_QUERY(t.Data, '$.Addresses') AS Address FROM [Table1] t
result:
[
{
"ApartmentNumber": "1",
"City": "Rome",
"CountryCode": "IT",
"HouseNumber": "2",
"Post": "Rome",
"PostalCode": "11-111",
"Region": "Rome",
"Street": "Italian",
"StreetPrefix": "St.",
"TypeCode": "PERMANENT"
},
{
"ApartmentNumber": "11",
"City": "Madrid",
"CountryCode": "ES",
"HouseNumber": "22",
"Post": "Madrid",
"PostalCode": "11-111",
"Region": "Madrid",
"Street": "Spanish",
"StreetPrefix": "St.",
"TypeCode": "CORRESPONDENCE"
}
]
or this:
query:
select top 1 JSON_VALUE(t.Data, '$.PersonData.LastName') FROM [Table1] t where ISJSON(t.Data) > 0 and JSON_VALUE(pd.BusinessPartner, '$.PersonData.Gender') = 'F'
result:
"Jones"
but when i to write similar query with Addresses as condition:
query:
select top 1 JSON_VALUE(t.Data, '$.Addresses.CountryCode') FROM [Table1] t where ISJSON(t.Data) > 0 and JSON_VALUE(t.Data,'$.Addresses.TypeCode') = 'CORRESPONDENCE'
I get empty string as the result.
Thanks in advance
From SQL Server 2016, you can query on JSON column. See the documentation : Work with JSON data
The interesting part for you it's Analyze JSON data with SQL queries.
This done :
select Id, PostalCode
from Address
CROSS APPLY OPENJSON (Address.Data, N'$.Addresses')
WITH (
TypeCode varchar(50) '$.TypeCode',
PostalCode varchar(50) '$.PostalCode'
) AS AddressesJsonData
WHERE TypeCode = N'PERMANENT'

Reading json array into rows in SQL Server

Given the sample json data below, how can I write a query to pull the array data all in one step? My goal is to have one row for each item in the ActionRecs array (4). My actual json is more complicated but I think this gives a good example of my goal.
declare #json2 nvarchar(max)
set #json2 = '{
"RequestId": "1",
"ActionRecs": [
{
"Type": "Submit",
"Employee": "Joe"
},
{
"Type": "Review",
"Employee": "Betty"
},
{
"Type": "Approve",
"Employee": "Sam"
},
{
"Type": "Approve",
"Employee": "Bill"
}
]
}'
SELECT x.*
, JSON_QUERY(#json2, '$.ActionRecs') as ActionArray
from OPENJSON(#json2)
with (Id varchar(5) '$.RequestId') as x
One possible approach is to use OPENJSON() with explicit schema and an additional CROSS APPLY operator:
DECLARE #json nvarchar(max)
SET #json = N'{
"RequestId": "1",
"ActionRecs": [
{"Type": "Submit", "Employee": "Joe"},
{"Type": "Review", "Employee": "Betty"},
{"Type": "Approve", "Employee": "Sam"},
{"Type": "Approve", "Employee": "Bill"}
]
}'
SELECT i.Id, a.[Type], a.[Employee]
FROM OPENJSON(#json) WITH (
Id varchar(5) '$.RequestId',
ActionRecs nvarchar(max) '$.ActionRecs' AS JSON
) AS i
CROSS APPLY OPENJSON(i.ActionRecs) WITH (
[Type] nvarchar(max) '$.Type',
[Employee] nvarchar(max) '$.Employee'
) a
Output:
Id Type Employee
1 Submit Joe
1 Review Betty
1 Approve Sam
1 Approve Bill

SQL Server - How to transform JSON to Relational database

How can we use SQL to Convert a JSON statement into different tables?
For example we have JSON:
{"table1":
{"Name":"table1","Items":
[{"Id":1,"FirstName":"John",
"LastName":"Wen","Country":"UK",
"PostCode":1234,"Status":false,
"Date":"2018-09-18T08:30:32.91",}]},
"table2":
{"Name":"table2","Items":
[{"Id":1,"Name":"leo",
"StudentId":102,"CreatedDate":"2018-09-18","Location":"USA"}]}}
In the relational database, we will get two tables once the JSON is converted
For example, schema 'Table1':
Id FirstName LastName Country PostCode Status Date
1 John Wen UK 1234 false 2018-09-18T08:30:32.91
And the 'Table2' will look like:
Id Name StudentId CreateDate Location
1 Leo 102 2018-9-18 USA
Could anyone please give any advices on it.
You can do this using openjson and json_value functions. Try the following:
Declare #json nvarchar(max),#table1Items nvarchar(max), #table2Items nvarchar(max)
set #json='{
"table1": {
"Name": "table1",
"Items": [{
"Id": 1,
"FirstName": "John",
"LastName": "Wen",
"Country": "UK",
"PostCode": 1234,
"Status": false,
"Date": "2018-09-18T08:30:32.91"
}, {
"Id": 2,
"FirstName": "John1",
"LastName": "Wen1",
"Country": "UK1",
"PostCode": 12341,
"Status": true,
"Date": "2018-09-15T08:30:32.91"
}]
},
"table2": {
"Name": "table2",
"Items": [{
"Id": 1,
"Name": "leo",
"StudentId": 102,
"CreatedDate": "2018-09-18",
"Location": "USA"
}]
}
}'
set #table1Items=(select value from OpenJSON((select value from OpenJSON(#Json) where [key]='table1')) where [key]='Items')
set #table2Items=(select value from OpenJSON((select value from OpenJSON(#Json) where [key]='table2')) where [key]='Items')
--select for table 1
select JSON_VALUE(val,'$.Id') as ID,
JSON_VALUE(val,'$.FirstName') as FirstName,
JSON_VALUE(val,'$.LastName') as LastName,
JSON_VALUE(val,'$.Country') as Country,
JSON_VALUE(val,'$.PostCode') as PostCode,
JSON_VALUE(val,'$.Status') as Status,
JSON_VALUE(val,'$.Date') as Date
from
(
select value as val from openJSON(#table1Items)
) AS Table1JSON
--select for table 1
select JSON_VALUE(val,'$.Id') as ID,
JSON_VALUE(val,'$.Name') as FirstName,
JSON_VALUE(val,'$.StudentId') as LastName,
JSON_VALUE(val,'$.CreatedDate') as Country,
JSON_VALUE(val,'$.Location') as PostCode
from
(
select value as val from openJSON(#table2Items)
) AS Table2JSON
It is working exactly as you wanted. At the end, the two select statements return the tables as you mentioned. Just add them to your desired table using insert into select. I have also tried adding another object to table1 array and verified that it is working fine i.e. returning two rows for two objects. Hope this helps
If SQL Version 2016+ use OPENJSON AND with_clause:
https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-2017
DECLARE #JsonData NVARCHAR(MAX);
SET #JsonData = N'
{
"table1": {
"Name": "table1",
"Items": [
{
"Id": 1,
"FirstName": "John",
"LastName": "Wen",
"Country": "UK",
"PostCode": 1234,
"Status": false,
"Date": "2018-09-18T08:30:32.91"
},
{
"Id": 2,
"FirstName": "John1",
"LastName": "Wen1",
"Country": "UK1",
"PostCode": 12341,
"Status": true,
"Date": "2018-09-15T08:30:32.91"
}
]
},
"table2": {
"Name": "table2",
"Items": [
{
"Id": 1,
"Name": "leo",
"StudentId": 102,
"CreatedDate": "2018-09-18",
"Location": "USA"
}
]
}
}
';
--Table1
SELECT [a].[Id]
, [a].[FistName]
, [a].[Lastname]
, [a].[Country]
, [a].[PostCode]
, [a].[Status]
, [a].[Date]
FROM
OPENJSON(#JsonData, '$.table1.Items')
WITH (
[Id] INT '$.Id'
, [FistName] NVARCHAR(200) '$.FirstName'
, [Lastname] NVARCHAR(200) '$.LastName'
, [Country] NVARCHAR(200) '$.Country'
, [PostCode] NVARCHAR(200) '$.PostCode'
, [Status] NVARCHAR(200) '$.Status'
, [Date] DATETIME '$.Date'
) [a];
--Table2
SELECT [a].[Id]
, [a].[Name]
, [a].[StudentId]
, [a].[CreatedDate]
, [a].[Location]
FROM
OPENJSON(#JsonData, '$.table2.Items')
WITH (
[Id] INT '$.Id'
, [Name] NVARCHAR(200) '$.Name'
, [StudentId] INT '$.StudentId'
, [CreatedDate] DATETIME '$.CreatedDate'
, [Location] NVARCHAR(200) '$.Location'
) [a];
Try using OPENJSON function in SQL Server:
ReferenceLink_1
ReferenceLink_2