SQL 2017 : Need to convert json with column name as a value and actual value is value of another one - sql-server-2017

HI I need to convert Json stored in 1 of the columns in a table to flat tables with specific fields.
Note : Column names are not always ""Request type,Country...".Columsn are dynamic and should be picked from value in "Name"
Below is the json from 1 row.
{"JobID":1,"ItemID":1,"Attributes":[{"ID":1,"Name":"Request Type","Value":"1","ValueString":"Buy"},{"ID":3,"Name":"Country","Value":"2","ValueString":"USA"},{"ID":5,"Name":"Number","Value":"1","ValueString":"1"}]}
I need this to be converted as in attached format

As a starter you should check OPENJSON:
DECLARE #j NVARCHAR(MAX) = '{"JobID":1,"ItemID":1,"Attributes":[{"ID":1,"Name":"Request Type","Value":"1","ValueString":"Buy"},{"ID":3,"Name":"Country","Value":"2","ValueString":"USA"},{"ID":5,"Name":"Number","Value":"1","ValueString":"1"}]}'
And query:
SELECT *
FROM OPENJSON(#j)
WITH (JobID INT '$.JobID',
ItemId INT '$.ItemID',
[Request_Type] NVARCHAR(100) '$.Attributes[0].ValueString',
Country NVARCHAR(100) '$.Attributes[1].ValueString',
[Number] NVARCHAR(100) '$.Attributes[2].ValueString'
);
DBFiddle Demo

Related

Select specific value from JSON list with SQL

Suppose I have a table column with person data organized as a JSON array, with categories and names.
In SQL, I can then easily select the data for a specific element in the array:
SELECT JSON_VALUE('{ "Persons": [{"PersonCat":"1","Name":"John"},{"PersonCat":"2","Name":"Henry"}]}','$.Persons[0].Name') AS SelectedPerson
I will then get "John".
But what if I want the person with "PersonCat" = 2? And null if PersonCat does not exist in the list?
I'm not sure it is possible to do this with the JSON_VALUE method, but it is possible using OPENJSON
DECLARE #json nvarchar(max)
SET #json = '{ "Persons": [{"PersonCat":"1","Name":"John"},{"PersonCat":"2","Name":"Henry"},{"Name":"Bob"}]}'
SELECT[PersonCat], [Name]
FROM OPENJSON(#json, '$.Persons')
WITH (
PersonCat NVARCHAR(512) '$.PersonCat',
[Name] NVARCHAR(512) '$.Name'
)
You can then add a WHERE clause to the SELECT to find the relevant PersonCat value (note: where the PersonCat property is missing from the array entry, the PersonCat column will be NULL)

Optimal way to SET/DECLARE a list in SQL query?

I am writing a SQL Query based of user input, as these inputs will change on a daily basis.
The goal of the query is to pull all data for only the ID's in the user-defined list. Example below-
However, I am getting the following error:
"Conversion failed when converting the varchar [...] to data type int"
Any idea on what the optimal way to specify a list and use that list at the "ID in (..)" clause?
I have tried converting the ID list into strings, but still receiving a similar error.
id_list = [12,16,22,42,1,24]
date = '2020-12-18'
query = (
"""
DECLARE #id varchar(1000), #date datetime
SET #id = '{}'
SET #date = '{}'
SELECT * from TABLE where ID in (#id) and Date = #Date
"""
.format(id_list,date))
The desired result is for a query to be able to take a list of IDs that could be utilized in the clause.
id in #id
SQL Server doesn't support lists or arrays. So the best method is a table:
declare #id_list table (id int);
insert into #idlist (id)
values (12), (16), (22), (42), (1), (24);
You can then use this wherever you would use a table variable. For instance:
where id in (select id from #id_list)

Parse JSON in SQL

I'm looking to parse a single return in JSON into multiple rows.
The string is this -
{"policy_ids":["INZP2981-11000002","INZP-00001786","0AAAA01PC06"]}
I want to just parse this so that it is a row for each policy_ids. I've tried using OpenJSON WITH however I keep returning NULL values.
DECLARE #json NVARCHAR(MAX) ;
SET #json = N'{"policy_ids":["INZP2981-11000002","INZP-00001786","0AAAA01PC06"]}' ;
SELECT
*
FROM
OPENJSON(#json)
WITH (
policy_ids varchar(200) '$.policy_ids'
)
Help is appreciated.
You need a different statement to parse the $.policy_ids JSON array. You may try tou use OPENJSON() with default schema (without the WITH clause). In this case the result is a table with columns key, value and type and the value column returns the value of each item in the input array.
DECLARE #json NVARCHAR(MAX) ;
SET #json = N'{"policy_ids":["INZP2981-11000002","INZP-00001786","0AAAA01PC06"]}' ;
SELECT [value] AS policy_id
FROM OPENJSON(#json, '$.policy_ids')
Result:
policy_id
-----------------
INZP2981-11000002
INZP-00001786
0AAAA01PC06
If you want to use an explicit schema, the statement is:
SELECT *
FROM OPENJSON(#json, '$.policy_ids') WITH (
policy_id varchar(200) '$'
)

SQL - openjson to extract key from json

Below #json contains 3 data object within an array. After using OPENJSON to extract these objects to a Table variable, please see the output attached.
DECLARE #json NVARCHAR(MAX);
SET #json = N'[{"Container":"MSKU2913236","Seal":"ML-TH4773979","Size":"20","Temperature":"-20","TareWeight":"3.132","CreatedDate":"02-02-2018 00:00:00","Comment":null,"NetWeight":"21.445","TempRec#":null},{"Container":"MSKU3432702","Seal":"ML-TH4773972","Size":"20","Temperature":"-40","TareWeight":"2.872","CreatedDate":"02-02-2018 00:00:00","Comment":null,"NetWeight":"23.932","TempRec#":"TR12345"},{"Container":"MSKU4043053","Seal":"ML-TH4773973","Size":"20","Temperature":"-20","TareWeight":"2.995","CreatedDate":"02-02-2018 00:00:00","Comment":null,"NetWeight":"22.4","TempRec#":null}]';
DECLARE #ContainerTable TABLE(
[Key] NVARCHAR(100),
[Data] NVARCHAR(MAX)
);
INSERT INTO #ContainerTable
SELECT [key], [value] FROM OPENJSON(#json)
SELECT * FROM #ContainerTable
Output
Objective is to replace the Key column values with the Container property value from json in the Data column for all 3 rows.
Expected Output
Note: Expected output is hard coded and it only shows the one row but same is required for all rows.
You could use JSON_VALUE:
INSERT INTO #ContainerTable([Key], [Data])
SELECT JSON_VALUE([value],'$.Container'), [value]
FROM OPENJSON(#json);
DBFiddle Demo

How to display XML column data

I have a table column consist with the XML files. I want to read XML data and display it.
I come up with the following code. But it read only one row in the column
want to display other XML data also
declare #xml xml
select #xml = event_data_XML from #temp
SELECT * FROM (
SELECT
CAST(f.x.query('data(#name)') as varchar(150)) as data_name,
CAST(f.x.query('data(value)') as varchar(150)) as data_value
FROM #xml.nodes('/event') as t(n)
CROSS APPLY t.n.nodes('data') as f(x)) X
PIVOT (MAX(data_value) FOR data_name IN (NTDomainName, DatabaseName, ServerName)) as pvt
Output should be like this(NTDomainName, DatabaseName, ServerName are xml data)
There are a bunch of ways you could do this. I'll show you a way I think you'd find easiest.
To start, here's a table with a little test data:
CREATE TABLE dbo.stuff (
id int identity (1,1) primary key
, event_data_xml xml
, create_date datetime default(getdate())
, is_active bit default(1)
);
INSERT INTO dbo.stuff (event_data_xml)
VALUES ('<event name="thing" package="as">something</event>')
INSERT INTO dbo.stuff (event_data_xml)
VALUES ('<event name="otherthing" package="as">something else</event>')
---All records
SELECT * FROM dbo.[stuff];
Make sense so far? Here's the query I'd use if I wanted to mix XML data and column data:
---Parsed up
SELECT event_data_xml.value('/event[1]', 'nvarchar(max)') AS [parsed element #text]
, event_data_xml.value('/event[1]/#name', 'nvarchar(max)') AS [parsed attribute value]
, create_date --column from table
FROM dbo.stuff
WHERE is_active = 1;
Using the value() function on the XML column passing in an xpath to what I want to display and SQL Server data type for how I want it returned.
Just make sure you're selecting a single value with your xpath expression.