Convert nested JSON to SQL table in SQL Server - sql

I am trying to convert a JSON file into a SQL table in SQL Server and running across an error that I cannot seem to find a solution for to save my life.
In addition to the error resolution, I would also like to go a step further and breakdown the employee ID values to not be in a single cell but rather split into separate rows.
Below is the code I am using which includes a sample JSON structure:
drop table if exists newtable1;
declare #json NVARCHAR(MAX)
--select #json=BulkColumn
--from openrowset (bulk 'C:\Users\hamza\Documents\Price Transparency\banking_sample.json',single_clob) as j;
= N'{
"comapny_name": "chase",
"company_type": "banking",
"last_updated_on": "2020-08-27",
"institutional":[{
"region_id": 1,
"groups": [{
"employee_id": [1111111111, 2222222222, 3333333333, 4444444444, 5555555555],
"site":{
"type": "atm",
"id": "11-1111111"
}
},{
"employee_id": [1111111111, 2222222222, 3333333333, 4444444444, 5555555555],
"site":{
"type": "branch",
"id": "22-2222222"
}
}]
},{
"region_id": 2,
"location": "new york city, ny"
}]
}';
select
JSON_VALUE(a.value,'$.company_name') as company_name,
JSON_VALUE(a.value,'$.company_type') as reporting_entity_type,
JSON_VALUE(a.value,'$.last_updated_on') as plan_name,
JSON_VALUE(b.value,'$.region_id') as prov_grp_id,
JSON_VALUE(b.value,'$.location') as loc,
JSON_VALUE(c.value,'$.employee_id') as npi,
JSON_VALUE(c.value,'$.site.type') as tin_type,
JSON_VALUE(c.value,'$.site.id') as tin_value
into newtable1
from openjson (#json) as a
cross apply openjson(a.value,'$.institutional') as b
cross apply openjson(b.value,'$.groups') as c;

Related

Get raw JSON of object when using OpenJSON

This is an awkward thing to word, so if this has been asked before sorry, I couldn't find any answers.
I'm taking JSON which is a list of objects and storing the fields in a table, however the JSON is from a third party and is prone to adding in new fields, so I'd like to also save the raw JSON of the object. So that if any unhandled fields were added we have the raw JSON, and can update the DB for those fields and run through the stored JSON, so no data is lost.
I can't however find or figure out how to just get the raw JSON of the current list item.
Basic OPENJSON I have:
DECLARE #JSON NVARCHAR(MAX) = '{"data": [
{ "id": 1,
"name": "foo",
"type": "bar",
"random": "Potato"},
{ "id": 2,
"name": "cake",
"type": "special",
"random": "unhandled field"}]}'
SELECT *
FROM OPENJSON(#JSON, '$.data')
WITH (
[id] INT '$.id',
[type] NVARCHAR(50) '$.type',
[name] NVARCHAR(50) '$.name'
) jsonData
but I can't find anywhere documenting how to also as a field get the entire JSON for the item.
My ideal tabled output being:
id
name
type
json
1
foo
bar
{ "id": 1,"name": "foo", "type": "bar", "random": "Potato"}
2
cake
special
{ "id": 2, "name": "cake", "type": "special", "random": "unhandled field"}

How to Set OPENJSON Path to Nested Array

I'm trying to set the path for my OPENJSON function for the nested array, but it's not working. Tried different variations and examples/resources I found online and still cannot figure it out.
Any ideas?
EDIT:
To be clear, I know how to do this with CROSSAPPLY and other methods. My question is in regards on how to do this specifically with the OPENJSON function's path parameter if possible.
Here's my code:
DECLARE #json NVARCHAR(MAX);
SET #json = '
{
"orders": [
{
"id":"1",
"date":"7/4/2020",
"orderlines": [
{"id": "1", "amount": 100},
{"id": "2", "amount": 200}
]
},
{
"id":"2",
"date":"7/4/2020",
"orderlines": [
{"id": "3", "amount": 300},
{"id": "4", "amount": 400}
]
}
]
}
'
-- None of these return results. How do I specify the path to the "orderlines" array?
SELECT * FROM OPENJSON(#json,'$.orderlines');
SELECT * FROM OPENJSON(#json,'$.orderlines[1]');
SELECT * FROM OPENJSON(#json,'$.orders.orderlines');
SELECT * FROM OPENJSON(#json,'$.orders.orderlines[1]');
-- This works:
SELECT * FROM OPENJSON(#json,'$.orders');
You can use WITH and put a name on inside values and use CROSS APPLY to use them in another OPENJSON. Now you can have all inside objects together.
SELECT orderlines.id, orderlines.amount
FROM OPENJSON(#json, '$.orders') WITH (orderlines NVARCHAR(MAX) '$.orderlines' AS JSON) orders
CROSS APPLY OPENJSON(orders.orderlines) WITH (id INT '$.id', amount INT '$.amount') orderlines
Learn more here.
Also if need to get specific item in array:
SELECT * FROM OPENJSON(#json, '$.orders[0].orderlines[0]')
-- OR
SELECT JSON_VALUE(#json, '$.orders[0].orderlines[0].amount')
To make it clear for others who may be viewing this, the part of Iman Kazemi's response that was the answer was the following of what he wrote:
SELECT * FROM OPENJSON(#json, '$.orders[0].orderlines[0]')
I neglected to specify the index on the order's array.
Thanks again to Iman.
You can try the following:
SELECT *
FROM OPENJSON (#json, '$.orders')
WITH (
id INT '$.id',
[date] VARCHAR(10) '$.date',
orderlines_id1 INT '$.orderlines[0].id',
orderlines_amount1 MONEY '$.orderlines[0].amount',
orderlines_id2 INT '$.orderlines[1].id',
orderlines_amount2 MONEY '$.orderlines[1].amount'
) AS Orders
Please see the db<>fiddle here.

MSSQL Query JSON displays Null value

I have a table PublicRelations with a column called Students in a SQL Server database called Subjects.
[
{ "Label": "Name", "ColumnValue": "Trudie" },
{ "Label": "Class", "ColumnValue": "PublicRelations" },
{ "Label": "Room", "ColumnValue": "8049" },
{ "Label": "HttpPath", "ColumnValue": "https://www.google.com/" }
]
I only get NULL when I run the below query using the Json_value. I'd like to get it to display the value from the array. I believe this may have to do with the 4000 character limit?
SELECT [StuduentID],
[Students],
--JSON_VALUE([Students],'$.ColumnValue') AS Name --Only returns NULL
FROM [Subjects].[dbo].[PublicRelations] c
CROSS APPLY OPENJSON(c.Students)
WITH ( Name int '$.Name',
Value nvarchar(255) '$.ColmunValue'
) AS jsonValues
WHERE jsonValues.ColumnValue = 'Trudie'
The query works and I can find what I need, but again, I only get NULL when I want to display that part of the JSON column in my results.
The statement is wrong and you has the following issues (as #MartinSmith already mentioned):
Syntax error - '$.ColmunValue' should be '$.ColumnValue'.
Wrong schema definition (the WITH clause) - I can't see Name key in the input JSON.
Wrong use of JSON_VALUE() - this function extracts scalar value from a JSON string, so JSON_VALUE([Students],'$.ColumnValue') returns NULL with this JSON input in lax mode.
You may try with the following statement (based on the statement in the question):
Table:
CREATE TABLE PublicRelations (
StudentID int,
Students nvarchar(1000))
INSERT INTO PublicRelations (StudentID, Students)
VALUES (1, N'[
{ "Label": "Name", "ColumnValue": "Trudie" },
{ "Label": "Class", "ColumnValue": "PublicRelations" },
{ "Label": "Room", "ColumnValue": "8049" },
{ "Label": "HttpPath", "ColumnValue": "https://www.google.com/" }
]')
Statement:
SELECT p.StudentID, j.*
FROM [PublicRelations] p
CROSS APPLY OPENJSON(p.Students) WITH (
Name nvarchar(50) '$.Label',
Value nvarchar(255) '$.ColumnValue'
) j
WHERE EXISTS (
SELECT 1
FROM OPENJSON(p.Students) WITH (Value nvarchar(255) '$.ColumnValue')
WHERE Value = N'Trudie'
) AND (j.Name IN ('Name', 'Class', 'Room'))
Result:
StudentID Name Value
1 Name Trudie
1 Class PublicRelations
1 Room 8049

Concatenate nested JSON in SQL Server

I am trying to concatenate nested JSON in SQL, how to do that.
Please help me out with this.
Example: I have JSON Like below.
[
{
"Name": "Cards",
"Value": [
"Pack of 24 Dare Cards"
],
"SourceSpecified": false,
"Any": []
},
{
"Name": "Boppers and Shot Glasses",
"Value": [
"12 Willy Shot Glass and 12 Hen Boppers"
],
"SourceSpecified": false,
"Any": []
}
]
I want Out Put:
Pack of 24 Dare Cards-12 Willy Shot Glass and 12 Hen Boppers
If Value always contains one element
DECLARE #JSON NVARCHAR(MAX) = ' [
{
"Name": "Cards",
"Value": [
"Pack of 24 Dare Cards"
],
"SourceSpecified": false,
"Any": []
},
{
"Name": "Boppers and Shot Glasses",
"Value": [
"12 Willy Shot Glass and 12 Hen Boppers"
],
"SourceSpecified": false,
"Any": []
}
]'
SELECT STRING_AGG(Val, '-')
FROM OPENJSON(#JSON)
WITH (Val NVARCHAR(MAX) '$.Value[0]')
Support of multiple values is also easy.
SELECT STRING_AGG(Val, '-')
FROM OPENJSON(#JSON)
WITH (VALUE NVARCHAR(MAX) '$.Value' AS JSON)
OUTER APPLY OPENJSON(VALUE) WITH (Val NVARCHAR(MAX) '$')
This one I achieved with creating a scalar-valued function to populate concatenated value.
Create FUNCTION [dbo].[test]
(
#VariationData nvarchar(max)
)
RETURNS nvarchar(max)
AS
BEGIN
Declare #val nvarchar(max)
select #val = COALESCE(#val+', ','')+ Value from OPENJSON(#VariationData)
With ([Value] NVARCHAR(MAX) N'$.Value[0]')
return #val
END
Call function with nested JSON value i.e
Select [dbo].[test] (#JSON);
This worked for me.

Insert an object into a JSON array in SQL Server

Every example that I've seen for JSON_MODIFY shows inserting a simple value such as a string into an array.
Suppose I have the following JSON stored in my SQL Server column:
[{"id": 1, "name": "One"}, {"id": 2, "name": "Two"}]
How do I append {"id": 3, "name": "Three"} to it?
When I try using JSON_MODIFY as shown below, a string is inserted:
UPDATE TheTable SET TheJSON = JSON_MODIFY(TheJSON, 'append $', N'{"id": 3, "name": "Three"}') WHERE Condition = 1;
Here is the resulting value for TheJSON column:
[{"id": 1, "name": "One"}, {"id": 2, "name": "Two"}, "{\"id\":3, \"name\": \"Three\"}"]
Other Attempts:
I noticed that I can create the JSON string that I want like this:
SELECT json.*
FROM TheTable t
CROSS APPLY OPENJSON(t.TheJSON) WITH (
id int N'$.id',
name nvarchar(100) N'$.name'
)
UNION ALL
SELECT 3 as id, N'Three' as name
FOR JSON AUTO;
However, when I go to try and use it in an update statement, it doesn't work:
UPDATE TheTable
SET TheJSON = (
SELECT json.* FROM TheTable t
CROSS APPLY OPENJSON(t.TheJSON) WITH (
id int N'$.id',
name nvarchar(100) N'$.name'
) as json
UNION ALL -- NO ERROR (and no update) when I remove UNION ALL+SELECT
SELECT 3 as id, N'Three' as name
FOR JSON AUTO
);
I get the following error:
Msg 1086, Level 15, State 1, Line 1: The FOR XML and FOR JSON clauses are invalid in views, inline functions, derived tables, and subqueries when they contain a set operator. To work around, wrap the SELECT containing a set operator using derived table or common table expression or view and apply FOR XML or FOR JSON on top of it.
You should wrap the third parameter of your JSON_MODIFY statement with JSON_QUERY():
UPDATE TheTable
SET TheJSON = JSON_MODIFY(TheJSON, 'append $', JSON_QUERY(N'{"id": 3, "name": "Three"}'))
WHERE Condition = 1;
Here is a complete sample:
DECLARE #TheTable table(TheJSON nvarchar(max), Condition int )
DECLARE #mystring nvarchar(100)='{"id": 3, "name": "Three"}'
INSERT INTO #TheTable SELECT '[{"id": 1, "name": "One"}, {"id": 2, "name": "Two"}]', 1
UPDATE #TheTable
SET TheJSON = JSON_MODIFY(TheJSON, 'append $', JSON_QUERY(N'{"id": 3, "name": "Three"}'))
WHERE Condition = 1;
SELECT TheJSON FROM #TheTable
This is the final output:
[{"id": 1, "name": "One"}, {"id": 2, "name": "Two"},{"id": 3, "name": "Three"}]
More info on JSON_QUERY here, and the explanation of the issue is here.