Nest Json Array merge - sql-server

I have a column saved json data in my table:
declare #json nvarchar(max)
set #json = N'
{
"Companies": [
{
"CompanyId": "A",
"Employee": null
},
{
"CompanyId": "B",
"Employee": [
{
"EmployeePictureId": null,
"Name": "Employee1"
},
{
"EmployeePictureId": "PictureId2",
"Name": "Employee2"
}
]
},
{
"CompanyId": "C",
"Employee": [
{
"EmployeePictureId": null,
"Name": "Employee3"
},
{
"EmployeePictureId": null,
"Name": "Employee4"
}
]
}
]
}
'
Is it posible to get the result like:
{
"EmployeePictureIds": ["PictureId2"]
}
using the Json_Query, Json_Value, OPENJSON...
Only get EmployeePictureId and skip empty(null) data
By the way, the count of elements in array are not sure.

In SQL Server 2017 you can use the following query:
select json_query(QUOTENAME(STRING_AGG('"' + STRING_ESCAPE( A.EmployeePictureId , 'json')
+ '"', char(44)))) as [EmployeePictureIds]
FROM OPENJSON(#json, '$.Companies')
WITH
(
CompanyId NVARCHAR(MAX),
Employee NVARCHAR(MAX) as json
) as B
cross apply openjson (B.Employee)
with
(
EmployeePictureId VARCHAR(50),
[Name] VARCHAR(50)
) as A
where A.EmployeePictureId is not null
for json path , WITHOUT_ARRAY_WRAPPER
Results for the JSON you provided:
Results adding another non null EmployeePictureId:

Related

Parse JSON file - Improve query in SQL Server

From this JSON File (just an example) I need to reach this final result
{
"Id": "101",
"name": "C01",
"testparameters": {
"room": [
{
"Floor": "First_Floor",
"Rooms": ["Room1", "Room2", "Room3"]
},
{
"Floor": "Second_Floor",
"Rooms": ["Room1", "Room2", "Room3"]
}
],
"area": [
{
"Name": "Area1",
"Subarea": ["Subarea1", "Subarea2", "Subarea3"]
},
{
"Name": "Area2",
"Subarea": ["Subarea4", "Subarea5"]
}
],
"requirements": [{
"condition": "",
"type": "type1",
"field1": "",
"field2": "aaaaa",
"operator": "",
"value2": ""
},
{
"condition": "AND",
"type": "type2",
"field1": "",
"field2": "numPersons",
"operator": ">",
"value2": "20"
},
{
"condition": "OR",
"type": "type2",
"field1": "",
"field2": "specification",
"operator": "=",
"value2": "wifi"
}
]
}
}
'
In one register I need to have all the information that is requested.
This is the first time that I need to parse a JSON file. After asking (a lot) I manage to reach the expected result by doing this:
Parsing JSON Example
However, I had to open the JSON file several times, and process each section apart. I'm wondering, how can I improve the code by reducing the number of times that I need to use the OPENJSON function, and in particular, how to rewrite the code snippet that handle the requirements section.
I must say, your desired result looks pretty de-normalized, you may want to rethink it.
Be that as it may, you can combine these quite easily, by using nested subqueries
SELECT
ID = JSON_VALUE(j.json, '$.Id'),
name = JSON_VALUE(j.json, '$.name'),
area = (
SELECT STRING_AGG(concat(d.a , ':', b.value),' - ')
from openjson(j.json, '$.testparameters.area')
with
(
a nvarchar(250) '$.Name',
s nvarchar(max) '$.Subarea' as json
) as d
cross apply openjson(d.s) as b
),
room = (
SELECT STRING_AGG(concat(c.f, ':', d.value), ' - ')
from openjson(j.json, '$.testparameters.room')
with(
f nvarchar(50) '$.Floor',
r nvarchar(Max) '$.Rooms' as json
) as c
cross apply openjson(c.r) as d
),
requirements = (
SELECT IIF(
SUBSTRING(requirements,1,3) = 'AND' or SUBSTRING(requirements,1,3) = 'OR',
SUBSTRING(requirements,5,LEN(requirements)),
requirements
)
from
(
select
STRING_AGG(CONCAT_WS(' ',
a.condition,
a.field2,
operator,
IIF (ISNUMERIC(a.value2) = 1,
a.value2,
CONCAT('''',a.value2,'''')
)
),
' ') as requirements
from openjson(j.json, '$.testparameters.requirements' )
with
(
condition nvarchar(255) '$.condition',
type nvarchar(255) '$.type',
field2 nvarchar(255) '$.field2',
operator nvarchar(255) '$.operator',
value2 nvarchar(255) '$.value2'
) a
where a.type = 'type2'
) a
)
FROM (VALUES(#json)) AS j(json) -- or you can reference a table

TSQL - Pivot not returning all rows

I have the following JSON array data set that needs to be parsed into 2 table rows:
[
{ "eid": "ABCDGD",
"name": "Carol E",
"email": "carole#gmail.com",
"role": "Recruiter"
},
{ "eid": "HDHDK",
"name": "Mark H",
"email": "markh#gmail.com",
"role": "Manager"
}
]
I need the code below to return both sets of employee information but it only returns one. How do I achieve this?
select p.* from
(SELECT j2.[key] as _keys, j2.Value as _vals
FROM OPENJSON(#c) j1
CROSS APPLY OPENJSON(j1.Value) j2
) as pds
PIVOT
(
max(pds._vals)
FOR pds._keys IN([eid], [name], [email], [role])
) AS p
SQLfiddle - http://sqlfiddle.com/#!18/9eecb/54970
No need to pivot, just specify your json columns and will give your desired results.
SELECT *
FROM OPENJSON(#c) WITH (
eid varchar(200) '$.eid',
name varchar(200) '$.name',
email varchar(200) '$.email',
role varchar(200) '$.role'
) j1
JSON is already maintaining a table kind structure in it and can be directly converted into table by using OPENJSON.
As the syntax of OPENJSON on MSDN website.
OPENJSON( jsonExpression [ , path ] ) [ <with_clause> ]
<with_clause> ::= WITH ( { colName type [ column_path ] [ AS JSON ] } [ ,...n ] )
Here just need to pass your column name as maintained in JSON and will convert your JSON into SQL Table.
You may find more details on this link.
For your above query you may try this.
DECLARE #json NVARCHAR(MAX)
SET #json =
N'[
{ "eid": "ABCDGD",
"name": "Carol E",
"email": "carole#gmail.com",
"role": "Recruiter"
},
{ "eid": "HDHDK",
"name": "Mark H",
"email": "markh#gmail.com",
"role": "Manager"
}
]'
SELECT *
FROM OPENJSON(#json)
WITH (
eid nvarchar(50) '$.eid',
name nvarchar(50) '$.name',
email nvarchar(50) '$.email',
role nvarchar(50) '$.role',
)

How to join JSON to update multiple rows by primary key

I am trying to update a log with JSON in SQL Server 2017. I can update a data point with json_value, which covers a few cases, but would ultimately like to join in incoming JSON.
Sample table:
key | col_1 | col_2 | col_3
----+-------------------------------+---------------|-----------------
1 | json.lines[0].data.meta.data | json.lines[0] | json.header.note
2 | json.lines[1].data.meta.data} | json.lines[1] | json.header.note
3 | json.lines[2].data.meta.data} | json.lines[2] | json.header.note
I'd like to update a single property in col_1 and update col_2 with an object as as as string.
Sample JSON:
declare #json nvarchar(max) = '[{
header: {
note: 'some note'
}, lines: [{
data {
id: {
key: 0,
name: 'item_1'
},
meta: {
data: 'item_1_data'
}
}, {...}, {...}
}]
}]'
Query:
update logTable set
col_1 = json_value(#json,'$.lines[__index__].data.meta.data'), -- what would the syntax for __index__ be?
col_2 = j.lines[key], -- pseudo code
col_3 = json_value(#json, '$'.header.note')
inner join openjson(#json) j
on json_value(#json,'$.line[?].id.key') = logTable..key -- ? denotes indices that I'd like to iterate = join over
Expected Output:
key | col_1 | col_2 | col_3
----+---------------+----------------------------|---------
1 | 'item_1_data' | 'data: { id: { key: 0...}' | '{header: { note: ...} }'
2 | 'item_2_data' | 'data: { id: { key: 1...}' | '{header: { note: ...} }'
3 | 'item_3_data' | 'data: { id: { key: 2...}' | '{header: { note: ...} }'
I'm not sure how to handle iterating over the $.line indices, but think a join would solve this if properly implemented.
How can I join to arrays of objects to update SQL rows by primary key?
Original answer:
You may try to parse your JSON using OPENJSON with explicit schema (note, that your JSON is not valid):
Table and JSON:
CREATE TABLE #Data (
[key] int,
col_1 nvarchar(100),
col_2 nvarchar(max)
)
INSERT INTO #Data
([key], [col_1], [col_2])
VALUES
(1, N'', N''),
(2, N'', N''),
(3, N'', N'')
DECLARE #json nvarchar(max) = N'[{
"lines": [
{
"data": {
"id": {
"key": 1,
"name": "item_1"
},
"meta": {
"data": "item_1_data"
}
}
},
{
"data": {
"id": {
"key": 2,
"name": "item_2"
},
"meta": {
"data": "item_2_data"
}
}
},
{
"data": {
"id": {
"key": 3,
"name": "item_3"
},
"meta": {
"data": "item_3_data"
}
}
}
]
}]'
Statement:
UPDATE #Data
SET
col_1 = j.metadata,
col_2 = j.data
FROM #Data
INNER JOIN (
SELECT *
FROM OPENJSON(#json, '$[0].lines') WITH (
[key] int '$.data.id.key',
metadata nvarchar(100) '$.data.meta.data',
data nvarchar(max) '$' AS JSON
)
) j ON #Data.[key] = j.[key]
Update:
Header is common for all rows, so use JSON_QUERY() to update the table:
Table and JSON:
CREATE TABLE #Data (
[key] int,
col_1 nvarchar(100),
col_2 nvarchar(max),
col_3 nvarchar(max)
)
INSERT INTO #Data
([key], col_1, col_2, col_3)
VALUES
(1, N'', N'', N''),
(2, N'', N'', N''),
(3, N'', N'', N'')
DECLARE #json nvarchar(max) = N'[{
"header": {
"note": "some note"
},
"lines": [
{
"data": {
"id": {
"key": 1,
"name": "item_1"
},
"meta": {
"data": "item_1_data"
}
}
},
{
"data": {
"id": {
"key": 2,
"name": "item_2"
},
"meta": {
"data": "item_2_data"
}
}
},
{
"data": {
"id": {
"key": 3,
"name": "item_3"
},
"meta": {
"data": "item_3_data"
}
}
}
]
}]'
Statement:
UPDATE #Data
SET
col_1 = j.metadata,
col_2 = j.data,
col_3 = JSON_QUERY(#json, '$[0].header')
FROM #Data
INNER JOIN (
SELECT *
FROM OPENJSON(#json, '$[0].lines') WITH (
[key] int '$.data.id.key',
metadata nvarchar(100) '$.data.meta.data',
data nvarchar(max) '$' AS JSON
)
) j ON #Data.[key] = j.[key]

How can i do a join with a GEOJson file and a table that exists already in the database?

I have a file with GEOJson data like so:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-73.759739, 42.61379],
[-73.759565, 42.614179],
[-73.752172, 42.614284999999995],
[-73.744867, 42.617281],
[-73.743042, 42.628958999999995],
[-73.74260799999999, 42.631581999999995],
[-73.734443, 42.631879999999995],
[-73.733936, 42.632020999999995],
[-73.73479499999999, 42.636396],
[-73.73097299999999, 42.643890999999996],
[-73.759739, 42.61379]
],
[[-73.72579, 42.650059], [-73.725143, 42.649788], [-73.725071, 42.649817], [-73.724823, 42.650282999999995], [-73.72552499999999, 42.650486], [-73.72579, 42.650059]]
]
},
"properties": { "STATEFP": "36", "UNSDLEA": "09630", "AFFGEOID": "9700000US3609630", "GEOID": "3609630", "NAME": "East Greenbush Central School District", "LSAD": "00", "ALAND": 195779723, "AWATER": 2721773 }
},
{
"type": "Feature",
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[[[-73.64970199999999, 42.351976], [-73.647074, 42.352069], [-73.647874, 42.353819], [-73.644886, 42.353538], [-73.640999, 42.354502], [-73.640935, 42.350439], [-73.64918399999999, 42.350263], [-73.64970199999999, 42.351976]]],
[
[
[-73.65831, 42.392008],
[-73.656461, 42.394642],
[-73.656983, 42.398876],
[-73.653469, 42.398039999999995],
[-73.65123799999999, 42.396592],
[-73.647519, 42.395765],
[-73.64356599999999, 42.392081],
[-73.649436, 42.392233],
[-73.652639, 42.393062],
[-73.65522, 42.39261],
[-73.655879, 42.390594],
[-73.658508, 42.391143],
[-73.65831, 42.392008]
]
],
[
[
[-73.77776399999999, 42.424766999999996],
[-73.775817, 42.429938],
[-73.774451, 42.435269],
[-73.77367, 42.44404],
[-73.773833, 42.449467999999996],
[-73.77420099999999, 42.451465999999996],
[-73.77553499999999, 42.451522999999995],
[-73.776663, 42.452602999999996],
[-73.77599, 42.454141],
[-73.777172, 42.455293999999995],
[-73.77776399999999, 42.424766999999996]
]
]
]
},
"properties": { "STATEFP": "36", "UNSDLEA": "15210", "AFFGEOID": "9700000US3615210", "GEOID": "3615210", "NAME": "Kinderhook Central School District (Ichabod Crane)", "LSAD": "00", "ALAND": 202445671, "AWATER": 9611722 }
}
]
}
How I can do a join where I can select the entire record E.g.
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-73.759739, 42.61379],
[-73.759565, 42.614179],
[-73.752172, 42.614284999999995],
[-73.744867, 42.617281],
[-73.743042, 42.628958999999995],
[-73.74260799999999, 42.631581999999995],
[-73.734443, 42.631879999999995],
[-73.733936, 42.632020999999995],
[-73.73479499999999, 42.636396],
[-73.73097299999999, 42.643890999999996],
[-73.759739, 42.61379]
],
[[-73.72579, 42.650059], [-73.725143, 42.649788], [-73.725071, 42.649817], [-73.724823, 42.650282999999995], [-73.72552499999999, 42.650486], [-73.72579, 42.650059]]
]
},
"properties": { "STATEFP": "36", "UNSDLEA": "09630", "AFFGEOID": "9700000US3609630", "GEOID": "3609630", "NAME": "East Greenbush Central School District", "LSAD": "00", "ALAND": 195779723, "AWATER": 2721773 }
}
where the name property from the file matches name column from my table??
My table is like so:
CREATE TABLE SCHOOL_INFO (
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](128) NOT NULL,
[address] [varchar](128) NOT NULL,
[city] [varchar](128) NOT NULL,
[state] [varchar](128) NOT NULL,
[zip] [varchar](16) NOT NULL,
[jsondata] [varchar](MAX) NOT NULL
)
All I want to do is insert the insert the matching json data into the jsondata column as a string. I do not need to use any of SQL spatial capabilities.
I figured out the following SQL:
Declare #JSON varchar(max)
SELECT #JSON = BulkColumn
FROM OPENROWSET (BULK 'C:\temp\nyusd.json', SINGLE_CLOB) as j
SELECT * FROM OPENJSON (#JSON, '$.features')
I tried to query for one record using the following SQL but I think I have the syntax wrong:
Declare #JSON varchar(max)
SELECT #JSON = BulkColumn
FROM OPENROWSET (BULK 'C:\temp\nyusd.json', SINGLE_CLOB) as j
SELECT * FROM OPENJSON (#JSON, '$.features') where JSON_VALUE(#JSON, '$.features.properties.Name') = 'East Greenbush Central School District';
Can someone point me in the right direction?
Thanks!
Please try:
Declare #JSON nvarchar(max)
SELECT #JSON = BulkColumn
FROM OPENROWSET (BULK 'C:\temp\nyusd.json', SINGLE_CLOB) as j
select *
From
(
SELECT * FROM OPENJSON (#JSON, '$.features')
)x
WHERE JSON_VALUE(x.[value], '$.properties.NAME') = 'East Greenbush Central School District'

SQL Server JSON Array

I have some JSON that I would like to parse in SQL Server 2016. There is a hierarchy structure with arrays. I would like to write a query that parses the whole hierarchy more efficiently, I have challenges trying to access embedded arrays especially anything under "DealerPrefLocation", while I have no problems accessing anything under "DealerInformation", below is my sample JSON:
{
"DealerInformation": {
"Altername": [
{
"firstName": "two",
"lastName": "one",
"middleName": null,
"otherNameExplanation": "change"
}
],
"DealerType": {
"id": "87ab-098ng-2345li",
"name": "DMD"
},
"firstName": "PK",
"middleName": null,
"lastName": "KPK",
"primaryDealerState": "AP",
"otherDealerState": [
"AP",
"MP"]
},
"DealerPrefLocation": [
{
"PrefLocation": [
{
"address": {
"address1": "fort warangal",
"address2": "east",
"addressStandardizationSource": null,
"city": "warangal",
"country": "India"
},
"apptPhoneNumber": "989898989898",
"createdAt": null,
"phoneNumber": "989898989898"
}
],
"NonPrefLocation": [
{
"address": {
"address1": "fort Junction",
"address2": null,
"addressStandardizationSource": null
},
"createdAt": null,
"ServiceName": "H1",
"ServiceId": [
{
"ServiceGroupName": null,
"Type": "GROUP",
"ServiceNumber": "9999999"
}
]
}
],
"Inserted": null,
"Updated": null }
]
}
I did figure out how to query "DealerInformation" and arrays within it such as "AlterName" and "OtherDealerState", however I have challenges querying arrays under "DealerInformation"-->"PrefLocation"-->Address.
Please find my current query and output:
select
ID,
JSON_VALUE(VALUE_ID,'$.DealerInformation.firstName'),
JSON_VALUE(VALUE_ID,'$.DealerInformation.primaryDealerState'),
JSON_VALUE(A.VALUE,'$.firstName'),
JSON_VALUE(C.VALUE,'$.PrefLocation.address.address1')
from
Test_JSON_File
cross apply
openjson(Test_JSON_File.value_id,'$.DealerInformation.Altername')A
cross apply
openjson(Test_JSON_File.Test_JSON_CAQH.value_id,'$.DealerPrefLocation')C
The last column I selected is from "DealerPrefLocation" but I get only nulls, can someone help what am I missing in the SQL or what do I need to add?
Sorry, this answer is rather late...
I think, the most important information for you is the AS JSON within the WITH-clause. See how I use it:
DECLARE #json NVARCHAR(MAX) =
N' {
"DealerInformation": {
"Altername": [
{
"firstName": "two",
"lastName": "one",
"middleName": null,
"otherNameExplanation": "change"
}
],
"DealerType": {
"id": "87ab-098ng-2345li",
"name": "DMD"
},
"firstName": "PK",
"middleName": null,
"lastName": "KPK",
"primaryDealerState": "AP",
"otherDealerState": [
"AP",
"MP"]
},
"DealerPrefLocation": [
{
"PrefLocation": [
{
"address": {
"address1": "fort warangal",
"address2": "east",
"addressStandardizationSource": null,
"city": "warangal",
"country": "India"
},
"apptPhoneNumber": "989898989898",
"createdAt": null,
"phoneNumber": "989898989898"
}
],
"NonPrefLocation": [
{
"address": {
"address1": "fort Junction",
"address2": null,
"addressStandardizationSource": null
},
"createdAt": null,
"ServiceName": "H1",
"ServiceId": [
{
"ServiceGroupName": null,
"Type": "GROUP",
"ServiceNumber": "9999999"
}
]
}
],
"Inserted": null,
"Updated": null }
]
}';
--I'll pick at least one element out of each region. This should point you the way:
SELECT B.firstName
,B.middleName
,B.lastName
,JSON_VALUE(B.DealerType,'$.id') AS DealerTypeId
,B.PrimaryDealerState
,B.otherDealerState --You can dive deeper to parse that array
,JSON_VALUE(B.Altername,'$[0].firstName') AS Alter_firstName --there might be more...
,JSON_VALUE(C.PrefLocation,'$[0].address.address1') AS pref_address --there might be more...
,JSON_VALUE(C.PrefLocation,'$[0].apptPhoneNumber') AS pref_apptPhoneNumber
,JSON_VALUE(C.NonPrefLocation,'$[0].address.address1') AS nonpref_address --there might be more...
,JSON_VALUE(C.NonPrefLocation,'$[0].ServiceName') AS nonpref_ServiceName
FROM OPENJSON(#json)
WITH(DealerInformation NVARCHAR(MAX) AS JSON
,DealerPrefLocation NVARCHAR(MAX) AS JSON) A
OUTER APPLY OPENJSON(A.DealerInformation)
WITH(Altername NVARCHAR(MAX) AS JSON
,DealerType NVARCHAR(MAX) AS JSON
,firstName NVARCHAR(MAX)
,DealerType NVARCHAR(MAX) AS JSON
,middleName NVARCHAR(MAX)
,lastName NVARCHAR(MAX)
,primaryDealerState NVARCHAR(MAX)
,otherDealerState NVARCHAR(MAX) AS JSON) B
OUTER APPLY OPENJSON(A.DealerPrefLocation)
WITH(PrefLocation NVARCHAR(MAX) AS JSON
,NonPrefLocation NVARCHAR(MAX) AS JSON) C
UPDATE Select out of a table
Try this
SELECT B.firstName
,B.middleName
,B.lastName
,JSON_VALUE(B.DealerType,'$.id') AS DealerTypeId
,B.PrimaryDealerState
,B.otherDealerState --You can dive deeper to parse that array
,JSON_VALUE(B.Altername,'$[0].firstName') AS Alter_firstName --there might be more...
,JSON_VALUE(C.PrefLocation,'$[0].address.address1') AS pref_address --there might be more...
,JSON_VALUE(C.PrefLocation,'$[0].apptPhoneNumber') AS pref_apptPhoneNumber
,JSON_VALUE(C.NonPrefLocation,'$[0].address.address1') AS nonpref_address --there might be more...
,JSON_VALUE(C.NonPrefLocation,'$[0].ServiceName') AS nonpref_ServiceName
FROM Test_JSON_File
CROSS APPLY OPENJSON(value_id)
WITH(DealerInformation NVARCHAR(MAX) AS JSON
,DealerPrefLocation NVARCHAR(MAX) AS JSON) A
OUTER APPLY OPENJSON(A.DealerInformation)
WITH(Altername NVARCHAR(MAX) AS JSON
,DealerType NVARCHAR(MAX) AS JSON
,firstName NVARCHAR(MAX)
,DealerType NVARCHAR(MAX) AS JSON
,middleName NVARCHAR(MAX)
,lastName NVARCHAR(MAX)
,primaryDealerState NVARCHAR(MAX)
,otherDealerState NVARCHAR(MAX) AS JSON) B
OUTER APPLY OPENJSON(A.DealerPrefLocation)
WITH(PrefLocation NVARCHAR(MAX) AS JSON
,NonPrefLocation NVARCHAR(MAX) AS JSON) C;

Resources