Related
I'm trying to use the TSheets API to pull data into my internal database, but the responses come back in a way that I can't figure out how to efficiently get it into table structure.
I've simplified the response for demo purposes, but it basically looks like this:
{
"results": {
"users": {
"12345": {
"id": 12345,
"first_name": "Demo",
"last_name": "User",
"username": "demo#gmail.com",
"email": "demo#gmail.com"
},
"321123": {
"id": 321123,
"first_name": "John",
"last_name": "Wayne",
"username": "notreal#email.com",
"email": "notreal#email.com"
},
"98765": {
"id": 98765,
"first_name": "Suzie",
"last_name": "Q",
"username": "email#company.com",
"email": "email#company.com"
}
}
},
"more": false
}
Instead of an array of users, each user is listed as a separate property with the id as the name of the property. They use this pattern on all the endpoints, so I need a way to know what the structure of the response is going to be in order to query it like I'm used to.
I've written a statement that uses dynamic sql to get this into a table structure, but I was wondering if someone more skilled with the JSON functions could propose a better solution.
Here's my SQL code...
GO
--// simplifed version of the actual json response for security and demo purposes
DECLARE #user_response NVARCHAR(MAX) = N'
{
"results": {
"users": {
"12345": {
"id": 12345,
"first_name": "Demo",
"last_name": "User",
"username": "demo#gmail.com",
"email": "demo#gmail.com"
},
"321123": {
"id": 321123,
"first_name": "John",
"last_name": "Wayne",
"username": "notreal#email.com",
"email": "notreal#email.com"
},
"98765": {
"id": 98765,
"first_name": "Suzie",
"last_name": "Q",
"username": "email#company.com",
"email": "email#company.com"
}
}
},
"more": false
}
'
--// put users object into variable
DECLARE #users NVARCHAR(MAX) = (
SELECT users.users
FROM OPENJSON(#user_response)
WITH (results NVARCHAR(MAX) AS JSON
, more VARCHAR(20)) as body
CROSS APPLY OPENJSON(results)
WITH (users NVARCHAR(MAX) AS JSON) as users
)
--// extract the keys from the users object
DECLARE #keys TABLE ([key] VARCHAR(100), [index] INT)
INSERT INTO #keys
SELECT [key], ROW_NUMBER() OVER (ORDER BY [key]) 'index'
FROM OPENJSON(#users)
--// initialize looping variables
DECLARE #i INT = 1
, #key VARCHAR(100)
, #sql NVARCHAR(MAX)
SELECT #sql = 'DECLARE #user_response NVARCHAR(MAX) = N''' + #user_response + ''''
--// loop through keys and UNION individual queries on the original json response
WHILE (#i <= (SELECT MAX([index]) FROM #keys))
BEGIN
SELECT #key = (SELECT [key] FROM #keys WHERE [index] = #i)
SELECT #sql = #sql + CASE WHEN #i = 1 THEN '' ELSE 'UNION' END + '
SELECT user_data.*
FROM OPENJSON(#user_response)
WITH (results NVARCHAR(MAX) AS JSON)
CROSS APPLY OPENJSON(results)
WITH (users NVARCHAR(MAX) AS JSON)
CROSS APPLY OPENJSON(users)
WITH ([' + #key + '] NVARCHAR(MAX) AS JSON)
CROSS APPLY OPENJSON([' + #key + '])
WITH (id INT
, first_name VARCHAR(100)
, last_name VARCHAR(100)
, username VARCHAR(200)
, email VARCHAR(200)) as [user_data]'
SELECT #i = #i + 1
END
--// execute final dynamic query
EXEC sp_executesql #sql
The resultset of this statement looks like this:
|id |first_name|last_name|username |email |
|-----|----------|---------|-----------------|-----------------|
|98765|Suzie |Q |email#company.com|email#company.com|
|321123|John |Wayne |notreal#email.com|notreal#email.com|
|12345|Demo |User |demo#gmail.com |demo#gmail.com |
Thanks in advance for your ideas and feedback.
Like this:
select u.*
from openjson(#user_response, '$.results.users') d
cross apply
openjson(d.value)
with
(
id int '$.id',
first_name varchar(200) '$.first_name',
last_name varchar(200) '$.last_name',
username varchar(200) '$.username',
email varchar(200) '$.email'
) u
if you need it you can get the object name with d.[key]
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',
)
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'
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;
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: