TSQL - Pivot not returning all rows - sql-server

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',
)

Related

Read JSON data from sql server and convert to row and column

{
"product": "car",
"fuel": {
"Maruti": {
"Model": {
"LXI": [
{
"Price": "700000"
}
],
"VXI": [
{
"Price": "800000"
}
],
"ZXI": [
{
"Price": "900000"
}
]
}
}
}
}
}
i have this JSON stored in SQL table and need t fetch it from CarDetails Table
table structure is as below:
ID
JSONData(this col has JSON stored)
CreatedDate
there can be more models as well like 10 or 20 or 1000....... I need all different prices for this in SQL Server. Can anyone assist
I need this data as:
700000
800000
900000
can anyone help me out in this.
I tried cross apply but it did not helped.
Having the model names as property keys complicates things slightly, but it's still possible to extract this data with multiple cross applies of the OPENJSON() function, e.g.:
declare #demo table (
ID int,
JSONData nvarchar(max)
);
insert #demo (ID, JSONData) values (47, N'{
"product": "car",
"fuel": {
"Maruti": {
"Model": {
"LXI": [
{
"Price": "700000"
}
],
"VXI": [
{
"Price": "800000"
}
],
"ZXI": [
{
"Price": "900000"
}
]
}
}
}
}
}');
select ID, J.product, K.[key] as [Model], L.Price
from #demo
cross apply openjson(JSONData) with (
product nvarchar(50),
ModelJSON nvarchar(max) '$.fuel.Maruti.Model' as JSON
) J
cross apply openjson(J.ModelJSON) K -- default columns: [key],[value],[type]
cross apply openjson(K.[value]) with (
Price nvarchar(10)
) L;
Which yields the results:
ID
product
Model
Price
47
car
LXI
700000
47
car
VXI
800000
47
car
ZXI
900000

OPENJSON() optimization for poorly structured API response

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]

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

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'

Nest Json Array merge

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:

Resources