OPENJSON on JSON with double empty array - json

I have this JSON
{
"OrderHeader": [[
{
"OrderID": 100,
"CustomerID": 2000,
"OrderDetail":
{
"ProductID":2000,
"UnitPrice":350
}
}
]]
}
After the OrderHeader there is two [[.
I am not able to parse this JSON using the OPENJSON TSQL Command.
If it was just one [ then i would parse like
DECLARE #JSONData varchar(MAX) = '
{
"OrderHeader": [
{
"OrderID": 100,
"CustomerID": 2000,
"OrderDetail":
{
"ProductID": 2000,
"UnitPrice": 350
}
}
]
}
'
SELECT
OrderID, CustomerID, ProductID, UnitPrice
FROM OPENJSON (#JSONData)
WITH (
OrderHeader nvarchar(MAX) AS JSON
) AS Orders
CROSS APPLY OPENJSON(Orders.OrderHeader)
WITH
(
OrderID INT,
CustomerID INT,
OrderDetail nvarchar(MAX) AS JSON
) AS OrderDetail
CROSS APPLY OPENJSON(OrderDetail.OrderDetail)
WITH
(
ProductID INT,
UnitPrice INT
) ;
Please help to Parse with its with TWO [ as in the first sample
Thank you.

One method would be to double up the OPENJSONs, though I would personally suggest, if you can, fixing the JSON:
DECLARE #JSONData nvarchar(MAX) = N'
{
"OrderHeader": [[
{
"OrderID": 100,
"CustomerID": 2000,
"OrderDetail":
{
"ProductID": 2000,
"UnitPrice": 350
}
}
]]
}';
SELECT V.OrderID,
V.CustomerID,
OD.ProductID,
OD.UnitPrice
FROM OPENJSON(#JSONData)
WITH (OrderHeader nvarchar(MAX) AS JSON) OJ
CROSS APPLY OPENJSON(OJ.OrderHeader) OH
CROSS APPLY OPENJSON(OH.[value])
WITH (OrderID int,
CustomerID int,
OrderDetail nvarchar(MAX) AS JSON) V
CROSS APPLY OPENJSON(V.OrderDetail)
WITH (ProductID int,
UnitPrice int) OD;

The statement depends on the structure of the parsed JSON ( ... I hope I understand it correctly) and you may simplify your statement using only two OPENJSON() calls:
JSON (with one additional item in the nested JSON array):
DECLARE #JSONData varchar(MAX) = '
{
"OrderHeader": [[
{
"OrderID": 100,
"CustomerID": 2000,
"OrderDetail":
{
"ProductID":2000,
"UnitPrice":350
}
},
{
"OrderID": 200,
"CustomerID": 3000,
"OrderDetail":
{
"ProductID":2000,
"UnitPrice":350
}
}
]]
}'
Statement:
SELECT j2.*
FROM OPENJSON(#JSONData, '$.OrderHeader') j1
CROSS APPLY OPENJSON(j1.[value]) WITH (
OrderID INT '$.OrderID',
CustomerID INT '$.CustomerID',
ProductID INT '$.OrderDetail.ProductID',
UnitPrice INT' $.OrderDetail.UnitPrice'
) j2
Result:
OrderID CustomerID ProductID UnitPrice
100 2000 2000 350
200 3000 2000 350
Finally, if the $.OrderHeader JSON array always has a single item, the following statement is also an option:
SELECT *
FROM OPENJSON(#JSONData, '$.OrderHeader[0]') WITH (
OrderID INT '$.OrderID',
CustomerID INT '$.CustomerID',
ProductID INT '$.OrderDetail.ProductID',
UnitPrice INT' $.OrderDetail.UnitPrice'
)

Related

Flatten nested JSON data into SQL Server tables

I have a JSON file that contains transactions, and each transaction contains multiple items. I need to flatten the data into SQL Server tables using T-SQL.
I have tried different options to flatten it, but it looks like I am missing something. Anyone who has worked on a similar structure have any ideas how this could be accomplished? 
DECLARE #json NVARCHAR(MAX);
SELECT #json = JsonPath
FROM [dbo].[stg_transactionsJson] b;
SELECT
CONVERT(NVARCHAR(50), JSON_VALUE(c.Value, '$.orderId')) AS orderId,
CONVERT(DATETIME, JSON_VALUE(c.Value, '$.openTime')) AS openTime,
CONVERT(DATETIME, JSON_VALUE(c.Value, '$.closeTime')) AS closeTime,
CONVERT(NVARCHAR(50), JSON_VALUE(c.Value, '$.operatorId')) AS operatorId,
CONVERT(NVARCHAR(50), JSON_VALUE(c.Value, '$.terminalId')) AS terminalId,
CONVERT(NVARCHAR(50), JSON_VALUE(c.Value, '$.sessionId')) AS sessionId,
CONVERT(NVARCHAR(50), JSON_VALUE(p.Value, '$.productGroupId')) AS productGroupId,
CONVERT(NVARCHAR(150), JSON_VALUE(p.Value, '$.productId')) AS productId,
CONVERT(NVARCHAR(50), JSON_VALUE(p.Value, '$.quantity')) AS quantity,
CONVERT(NVARCHAR(150), JSON_VALUE(p.Value, '$.taxValue')) AS taxValue,
CONVERT(NVARCHAR(50), JSON_VALUE(p.Value, '$.value')) AS ProductValue,
CONVERT(NVARCHAR(150), JSON_VALUE(p.Value, '$.priceBandId')) AS priceBandId,
GETDATE() AS DateUpdated
FROM
OPENJSON(#json) AS c
OUTER APPLY
OPENJSON(c.Value, '$."products"') AS p;
And the sample JSON as follows
{
"orderId": 431,
"openTime": "2022-10-31T13:12:28",
"closeTime": "2022-10-31T13:12:32",
"operatorId": 7,
"terminalId": 4,
"sessionId": 1,
"products": [
{
"productId": 2632,
"productGroupId": 162,
"quantity": 1,
"taxValue": 0.58,
"value": 3.5,
"priceBandId": 2
},
{
"productId": 3224,
"productGroupId": 164,
"quantity": 1,
"taxValue": 0.08,
"value": 0.5,
"priceBandId": 2
}
],
"tenders": [
{
"tenderId": 2,
"value": 4.0
}
],
"type": 1,
"memberId": 1
}
You can Do it like this
First declare the values in an with clause and then cross apply the products
DECLARE #json NVARCHAR(MAX);
SET #json = '{
"orderId": 431,
"openTime": "2022-10-31T13:12:28",
"closeTime": "2022-10-31T13:12:32",
"operatorId": 7,
"terminalId": 4,
"sessionId": 1,
"products": [
{
"productId": 2632,
"productGroupId": 162,
"quantity": 1,
"taxValue": 0.58,
"value": 3.5,
"priceBandId": 2
},
{
"productId": 3224,
"productGroupId": 164,
"quantity": 1,
"taxValue": 0.08,
"value": 0.5,
"priceBandId": 2
}
],
"tenders": [
{
"tenderId": 2,
"value": 4.0
}
],
"type": 1,
"memberId": 1
}
';
SELECT c.orderId
,c.openTime
,c.closeTime
,c.operatorId
,c.terminalId
,c.sessionId
, JSON_VALUE(p.Value, '$.productGroupId') productGroupId
, JSON_VALUE(p.Value, '$.productId') productId
, JSON_VALUE(p.Value, '$.quantity') quantity
, JSON_VALUE(p.Value, '$.taxValue') taxValue
, JSON_VALUE(p.Value, '$.value') value
, JSON_VALUE(p.Value, '$.priceBandId') priceBandId
,GETDATE() AS DateUpdated
FROM
OPENJSON(#json) WITH (
orderId int '$.orderId',
openTime date '$.openTime',
closeTime date '$.closeTime',
operatorId int '$.operatorId',
terminalId int '$.terminalId',
sessionId int '$.sessionId',
[products] NVARCHAR(MAX) as JSON) c
CROSS APPLY OPENJSON(c.products) p
orderId
openTime
closeTime
operatorId
terminalId
sessionId
productGroupId
productId
quantity
taxValue
value
priceBandId
DateUpdated
431
2022-10-31
2022-10-31
7
4
1
162
2632
1
0.58
3.5
2
2023-01-11 13:57:47.607
431
2022-10-31
2022-10-31
7
4
1
164
3224
1
0.08
0.5
2
2023-01-11 13:57:47.607
fiddle
The expected output defines the exact statement, but if you need to parse nested JSON content you may try a combination of:
OPENJSON() with explicit schema and the AS JSON modifier for nested JSON
additional APPLY operators for each nested level.
T-SQL:
SELECT
j1.orderId, j1.openTime, j1.closeTime, j1.operatorId, j1.terminalId, j1.sessionId, j1.type, j1.memberId,
j2.productGroupId, j2.productId, j2.quantity, j2.taxValue, j2.productValue, j2.priceBandId,
j3.tenderId, j3.tenderValue
FROM stg_transactionsJson s
OUTER APPLY OPENJSON(s.stg_transactionsJson) WITH (
orderId NVARCHAR(50) '$.orderId',
openTime DATETIME '$.openTime',
closeTime DATETIME '$.closeTime',
operatorId NVARCHAR(50) '$.operatorId',
terminalId NVARCHAR(50) '$.terminalId',
sessionId NVARCHAR(50) '$.sessionId',
products NVARCHAR(MAX) '$.products' AS JSON,
tenders NVARCHAR(MAX) '$.tenders' AS JSON,
type int '$.type',
memberId int '$.memberId'
) j1
OUTER APPLY OPENJSON(j1.products) WITH (
productGroupId NVARCHAR(50) '$.productGroupId',
productId NVARCHAR(150) '$.productId',
quantity NVARCHAR(50) '$.quantity',
taxValue NVARCHAR(150) '$.taxValue',
productValue NVARCHAR(50) '$.value',
priceBandId NVARCHAR(150)'$.priceBandId'
) j2
OUTER APPLY OPENJSON(j1.tenders) WITH (
tenderId NVARCHAR(150) '$.tenderId',
tenderValue NVARCHAR(50) '$.value'
) j3

SQL Parse Json array to rows

I'm trying to parse the 'custinfo' array to rows, rather than specific columns how I have in my query (there can be none or many values in the array)
DECLARE #json NVARCHAR(MAX) ='{
"customer": [
{
"id": "123",
"history": [
{
"id": "a123",
"dates": [
{
"date": "2022-03-19",
"details": {
"custinfo": [
"male",
"married"
],
"age": 40
}}]}]}]}'
SELECT
JSON_VALUE ( j.[value], '$.id' ) AS CustId,
JSON_VALUE ( m.[value], '$.id' ) AS CustId_Hist,
JSON_VALUE ( a1.[value], '$.date' ) AS date,
JSON_VALUE ( a1.[value], '$.details.age' ) AS age,
JSON_VALUE ( a1.[value], '$.details.custinfo[0]' ) AS custinfo0,
JSON_VALUE ( a1.[value], '$.details.custinfo[1]' ) AS custinfo1
FROM OPENJSON( #json, '$."customer"' ) j
CROSS APPLY OPENJSON ( j.[value], '$."history"' ) AS m
CROSS APPLY OPENJSON ( m.[value], '$."dates"' ) AS a1
Desired results:
Like I mentioned in the comments, I would switch to using WITH clauses and defining your columns and their data types. You can then also get the values, into 2 separate rows you want, with the following. Note tbhe extra OPENJSON at the end, which treats the custinfo as the array it is; returning 2 rows (1 for each value in the array):
DECLARE #json NVARCHAR(MAX) ='{
"customer": [
{
"id": "123",
"history": [
{
"id": "a123",
"dates": [
{
"date": "2022-03-19",
"details": {
"custinfo": [
"male",
"married"
],
"age": 40
}}]}]}]}';
SELECT c.id AS CustId,
h.id AS CustId_Hist,
d.date AS date,
d.age AS age,
ci.[value] AS custinfo
FROM OPENJSON( #json,'$.customer')
WITH (id int,
history nvarchar(MAX) AS JSON) c
CROSS APPLY OPENJSON (c.history)
WITH (id varchar(10),
dates nvarchar(MAX) AS JSON) h
CROSS APPLY OPENJSON (h.dates)
WITH(date date,
details nvarchar(MAX) AS JSON,
age int '$.details.age') d
CROSS APPLY OPENJSON(d.details,'$.custinfo') ci;

When insert JSON string to SQL table I only get the first record

I have the following json , when i am trying to extract it to sql i get only the first row can you please help.
DECLARE #json NVARCHAR(MAX);
SET #json = '{
"Reportno":{
"Env":{
"A":7140541,
"B":179001,
"C":"XML",
"D":"SLSPRV",
"F":90760,
"G":202104,
"H":2030,
"I":{
"J":20240118,
"K":202202014,
"L":22203,
"M":2020103,
"N":179001,
"O":9200005,
"P":{
"CustData":[
{
"CustCode":7295,
"Lines":{
"Barcode":13782,
"Qty":1,
"pack":"Box"
}
},
{
"CustCode":880,
"Lines":[
{
"Barcode":9245,
"Qty":2,
"pack":"unit"
},
{
"Barcode":5536,
"Qty":1,
"pack":"unit"
},
{
"Barcode":46199,
"Qty":3,
"pack":"Box"
},
{
"Barcode":738,
"Qty":1,
"pack":"unit"
},
{
"Barcode":149010,
"Qty":5,
"pack":"unit"
}
]
}
]
}
}
}
}
}'
SELECT *
FROM OPENJSON(#json, '$.Reportno.Env.I.P.CustData')
WITH (
CustCode varchar(150) '$.CustCode',
Barcode BIGINT '$.Lines.Barcode',
Qty SMALLINT '$.Lines.Qty',
pack NVARCHAR(max) '$.Lines.pack'
);
this is the resulte i get
this is what i need
Thank
You need to use 2 OPENJSON calls. The first for your CustData, adn then the 2nd for the nested JSON within Lines:
SELECT CD.CustCode,
L.Barcode,
L.Qty,
L.pack
FROM OPENJSON(#json, '$.Reportno.Env.I.P.CustData')
WITH (CustCode varchar(150) '$.CustCode',
Lines nvarchar(MAX) AS JSON) CD
CROSS APPLY OPENJSON(CD.Lines)
WITH(Barcode BIGINT '$.Barcode',
Qty SMALLINT '$.Qty',
pack NVARCHAR(max) '$.pack') L;

how to add key-value pair in json root node and convert it into table using SQL server

I have table people and it's maintain Four column which is Name ,TagName ,Value , Location.
I want to convert the tagname and value in json with name and location column as rootnode (Name & location same for multiple records)
Need output as :
{
"{"Name":"EMP1","Location":"mumbai"}": [
{
"TagName": "1",
"Value": "844.17769999999996"
},
{
"TagName": "abc",
"Value": "837.43679999999995"
},
{
"TagName": "pqr",
"Value": "0"
},
{
"TagName": "XYZ",
"Value": "1049.2429999999999"
}
]
}
please check the below query, In which I am trying to create json string using json path but stuck in root node.
SELECT TagName
,Value
FROM dbo.people
FOR JSON PATH, ROOT('')---
when I convert the above json into tabular format, required output as :
Name | Location |TagName| Value
EMP1 | Mumbai |1 | 844.17769999999996|
EMP1 | Mumbai |abc | 837.43679999999995|
.....
Your expected output is not a valid JSON, but you are probably looking for something like this:
Table:
CREATE TABLE People (
[Name] varchar(10),
[Location] varchar(50),
[TagName] varchar(3),
[Value] numeric(20, 14)
)
INSERT INTO People ([Name], [Location], [TagName], [Value])
VALUES
('EMP1', 'Mumbai', '1', 844.17769999999996),
('EMP1', 'Mumbai', 'abc', 837.43679999999995),
('EMP2', 'Mumbai', 'abc', 837.43679999999995)
Statement:
SELECT DISTINCT p.[Name], p.[Location], c.Items
FROM People p
CROSS APPLY (
SELECT [TagName], [Value]
FROM People
WHERE [Name] = p.[Name] AND [Location] = p.[Location]
FOR JSON AUTO
) c (Items)
FOR JSON PATH
Result:
[
{
"Name":"EMP1",
"Location":"Mumbai",
"Items":[
{
"TagName":"1",
"Value":844.17769999999996
},
{
"TagName":"abc",
"Value":837.43679999999995
}
]
},
{
"Name":"EMP2",
"Location":"Mumbai",
"Items":[
{
"TagName":"abc",
"Value":837.43679999999995
}
]
}
]
If you want to parse the generated JSON, you need to use OPENJSON() twice:
Generated JSON:
DECLARE #json varchar(max) = N'[
{
"Name":"EMP1",
"Location":"Mumbai",
"Items":[
{
"TagName":"1",
"Value":844.17769999999996
},
{
"TagName":"abc",
"Value":837.43679999999995
}
]
},
{
"Name":"EMP2",
"Location":"Mumbai",
"Items":[
{
"TagName":"abc",
"Value":837.43679999999995
}
]
}
]'
Statement:
SELECT j1.Name, j1.Location, j2.TagName, j2.Value
FROM OPENJSON(#json) WITH (
[Name] varchar(10) '$.Name',
[Location] varchar(50) '$.Location',
[Items] nvarchar(max) '$.Items' AS JSON
) j1
OUTER APPLY OPENJSON(j1.Items) WITH (
[TagName] varchar(3) '$.TagName',
[Value] numeric(20, 14) '$.Value'
) j2

How to call Json in sql query

I want to display the parameter ST and NextTime from table #json. The parameters id and Timestamp appear normally. I try the following but does not show any effect.Any possible answers?
My Json
{
"PCol": [{
"Id": 15,
"TimeStamp": "2018-02-1",
"Val": {
"States": [{
"Numbers": {
"Number": [5, 8]
},
"CS": {
"ST": "25"
},
"Changes": [{
"NextTime": 1
}]
}]
}
}]
}
My Sql Query
SELECT * FROM OPENJSON((select * from #json),N'$.PCol')
WITH (
[Id] INT N'$.Id ',
[TimeStamp] NVARCHAR(MAX) N'$.TimeStamp',
**[ST] INT N'$.Val.States.CS.ST'**
)
Thanks
Not going to lie, my OPENJSON knowledge is poor (so this might be able to be more succinct), however, this works:
DECLARE #JSON nvarchar(MAX) =
N' {
"PCol": [{
"Id": 15,
"TimeStamp": "2018-02-1",
"Val": {
"States": [{
"Numbers": {
"Number": [5, 8]
},
"CS": {
"ST": "25"
}
}]
}
}]
} ';
SELECT P.Id,
P.TimeStamp,
V.ST
FROM OPENJSON(#JSON,N'$.PCol') WITH ([Id] INT N'$.Id ',
[TimeStamp] NVARCHAR(MAX) N'$.TimeStamp',
[Vals] nvarchar(MAX) N'$.Val' AS JSON) P
CROSS APPLY OPENJSON(P.Vals,N'$.States') WITH (ST int N'$.CS.ST') V
For the latest JSON, this works:
SELECT P.Id,
P.TimeStamp,
V.ST,
C.NextTime
FROM OPENJSON(#JSON,N'$.PCol') WITH ([Id] INT N'$.Id ',
[TimeStamp] NVARCHAR(MAX) N'$.TimeStamp',
[Vals] nvarchar(MAX) N'$.Val' AS JSON) P
CROSS APPLY OPENJSON(P.Vals,N'$.States') WITH (ST int N'$.CS.ST',
[Changes] nvarchar(MAX) N'$.Changes' AS JSON) V
CROSS APPLY OPENJSON(V.[Changes]) WITH (NextTime int '$.NextTime') C