SQL query to JSON data - json

We've JSON entry in the MS SQL database. I would like to export JSON entry in the "Data" column which match with the list of EMPNO. Could someone please help?
ColumnName: Data
Data inside the column:
output:{
"Request":{
"Person":{
"DisplayName":"Test User",
"EMPNO":"000001",
"Entity":"01",
"Country":"AA"
},
"DomainOverride":null,
"ReasonForGen":"Only",
"Email":"123#test.com",
"CurrentSIP":"123#test.com"
},
"EmailAddress":"123#testcom",
"SIPAddress":"123#test.com",
"Status":"NoChange"
}
Query in layman language:
select DisplayName,EMPNO,Entity,Country,DomainOverride,ReasonForGen,Email
from Table1
where data.output.Request.EMPNO in ([EMPNO list])

You can use JSON_VALUE. Something like this:
select JSON_VALUE(data,'$.Output.Request.Person.DisplayName'), ...
from Table1
where JSON_VALUE(data,'$.Output.Request.Person.EMPNO') in ([EMPNO list])

You may try to use OPENJSON() to parse the JSON text and get objects and values from the JSON input as a table. You need to use OPENJSON() with explicit schema in the WITH clause to define the columns:
Table:
CREATE TABLE Data (
JsonData nvarchar(max)
)
INSERT INTO Data
(JsonData)
VALUES
(N'{
"output":{
"Request":{
"Person":{
"DisplayName":"Test User",
"EMPNO":"000001",
"Entity":"01",
"Country":"AA"
},
"DomainOverride":null,
"ReasonForGen":"Only",
"Email":"123#test.com",
"CurrentSIP":"123#test.com"
},
"EmailAddress":"123#testcom",
"SIPAddress":"123#test.com",
"Status":"NoChange"
}
}')
Statement:
SELECT
j.DisplayName,
j.EMPNO,
j.Entity,
j.Country,
j.DomainOverride,
j.ReasonForGen,
j.Email
FROM Data d
CROSS APPLY OPENJSON(d.JsonData) WITH (
EMPNO nvarchar(10) '$.output.Request.Person.EMPNO',
DisplayName nvarchar(50) '$.output.Request.Person.DisplayName',
EMPNO nvarchar(50) '$.output.Request.Person.EMPNO',
Entity nvarchar(50) '$.output.Request.Person.Entity',
Country nvarchar(50) '$.output.Request.Person.Country',
DomainOverride nvarchar(50) '$.output.Request.DomainOverride',
ReasonForGen nvarchar(50) '$.output.Request.ReasonForGen',
Email nvarchar(50) '$.output.Request.Email'
) j
-- Use additional WHERE clause
--WHERE j.EMPNO IN ('00001', '000002')
Result:
DisplayName EMPNO Entity Country DomainOverride ReasonForGen Email
Test User 000001 01 AA Only 123#test.com

Related

Querying XML in SQL Server

I'm a newbie to SQL Server. I have a table Accounts which is defined as:
OrganizationId int,
AccountDetails varchar(max)
The AccountDetails column contains XML data.
The data in the table looks like this:
1 | <Account><Id>100</Id><Name>A</Name></Account>
2 | <Account><Id>200</Id><Name>B</Name></Account>
3 | <Account><Id>300</Id><Name>C</Name></Account>
4 | <Account><Id>400</Id><Name>D</Name></Account>
I need write a SQL query to get the records from this table where AccountId is 200 or 400.
The query should return two rows (#2 and #4) in JSON format, like this:
result1 : { "account_id": 200, "account_name": B }
result2 : { "account_id": 400, "account_name": D }
I'm wondering how do I go about this?
Thank you.
For # 1 above, should I be trying to cast the AccountDetails column to XML type and then use "nodes" feature for querying/filtering?
For #2, I should be writing a SQL function to convert the XML to JSON first and querying XML to build the JSON as needed?
As already mentioned, it is much better to use a proper XML data type for the AccountDetails column.
Please try the following solution.
It will work starting from SQL Server 2016 onwards.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (OrganizationId INT IDENTITY PRIMARY KEY, AccountDetails NVARCHAR(MAX));
INSERT #tbl (AccountDetails) VALUES
('<Account><Id>100</Id><Name>A</Name></Account>'),
('<Account><Id>200</Id><Name>B</Name></Account>'),
('<Account><Id>300</Id><Name>C</Name></Account>'),
('<Account><Id>400</Id><Name>D</Name></Account>');
-- DDL and sample data population, end
;WITH rs AS
(
SELECT t.OrganizationId
, account_id = x.value('(/Account/Id/text())[1]', 'INT')
, account_name = x.value('(/Account/Name/text())[1]', 'VARCHAR(20)')
FROM #tbl AS t
CROSS APPLY (VALUES(TRY_CAST(AccountDetails AS XML))) AS t1(x)
)
SELECT *
, JSONData = (SELECT rs.account_id, rs.account_name FOR JSON PATH,WITHOUT_ARRAY_WRAPPER)
FROM rs
WHERE rs.account_id IN (200, 400);
Output
OrganizationId
account_id
account_name
JSONData
2
200
B
{"account_id":200,"account_name":"B"}
4
400
D
{"account_id":400,"account_name":"D"}

Convert select result that has JSON field to JSON and use that data with JSON_VALUE()

I have a table that has some columns.
One of these columns stores data in JSON format.
I select a row from this table with FOR JSON AUTO.
My problem is that SQL Server puts quotations around the value of JSON properties but I don't want this; because I want to use the values of inner JSON with JSON_VALUE(). What can I do?
Code:
SELECT TOP 1 *
FROM users;
Result:
name lastName age favorites
John Duo 20 {"city": "paris", "color": "blue", "sport": "football"}
Code:
SELECT TOP 1 *
FROM users
FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER;
Result:
{"name":"John","lastName":"Duo","age":20,"favorites":"{\"city\": \"paris\", \"color\": \"blue\", \"sport\": \"football\"}"}
Code:
SELECT JSON_VALUE(#user_json,'$.favorites.color')
Result:
NULL
I can use this trick to get values from inner JSON, but it's not clean.
Code:
SELECT JSON_VALUE(JSON_VALUE(#user_json,'$.favorites'), '$.color')
Result:
blue
How can I do this in a clean way?
Some code for testing in SQL Server:
DROP TABLE IF EXISTS #test_tbl;
DECLARE #user_json AS NVARCHAR(MAX);
SELECT 'John' AS Name, 'Duo' AS LastName, 20 AS Age, '{"city": "paris", "color": "blue", "sport": "football"}' AS favorites
INTO #test_tbl;
SET #user_json =
(
SELECT *
FROM #test_tbl
FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER
)
SELECT JSON_VALUE(#user_json,'$.favorites.color');
SELECT JSON_VALUE(JSON_VALUE(#user_json,'$.favorites'),'$.color');
You need to nest the favorites JSON using json_query(), e.g.:
SET #user_json =
(
SELECT Name, LastName, Age, json_query(favorites) as favorites
FROM #test_tbl
FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER
)
SELECT JSON_VALUE(#user_json,'$.favorites.color');
# (No column name)
# ----------------
# blue

How to correctly insert entries into `Json Array` within MySQL8?

I am using MySQL 8 and my table structure looks as below:
CREATE TABLE t1 (id INT, `group` VARCHAR(255), names JSON);
I am able to correctly insert records using the following INSERT statement:
INSERT INTO t1 VALUES
(1100000, 'group1', '[{"name": "name1", "type": "user"}, {"name": "name2", "type": "user"}, {"name": "techDept", "type": "dept"}]');
The JSON format has two types - user and dept
Now, I have an array of users and depts which looks as below:
SET #userlist = '["user4", "user5"]';
SET #deptlist = '["dept4", "dept5"]';
For a new group group2, I want to insert all those users and depts from within userlist and deptlist array into t1 table using a single query and I have written following query:
SELECT JSON_ARRAY_INSERT(JSON_OBJECT('name', #userlist , 'type', 'user'), ('name', #deptlist , 'type', 'gdl'));
Incorrect parameter count in the call to native function 'JSON_ARRAY_INSERT'

How to import JSON values inside MySQL (10.2.36-MariaDB) table?

I have the following JSON file :
{
"ID": 5464015,
"CUSTOMER_ID": 1088020,
"CUSOTMER_NAME": "My customer 1"
}
{
"ID": 5220812,
"CUSTOMER_ID": 523323,
"CUSOTMER_NAME": "My customer 2"
}
{
"ID": 5205039,
"CUSTOMER_ID": 1934806,
"CUSOTMER_NAME": "My customer 3"
}
From a shell script, I would like to import these values into a MariaDB table (MariaDB Server version : 10.2.36-MariaDB) with the related columns already created :
ID
CUSTOMER_ID
CUSTOMER_NAME
But for CUSTOMER_NAME, I don't want to import double quotes at the beginning and at the end of the value.
Is there a simple way to do it?
Or if not possible, If I have a txt or csv file like this :
5464015,1088020,"My customer 1"
5220812,523323,"My customer 2"
5205039,1934806,"My customer 3"
How to import it?
Many thanks
CREATE TABLE test (ID INT, CUSTOMER_ID INT, CUSTOMER_NAME VARCHAR(255));
SET #data := '
[ { "ID": 5464015,
"CUSTOMER_ID": 1088020,
"CUSTOMER_NAME": "My customer 1"
},
{ "ID": 5220812,
"CUSTOMER_ID": 523323,
"CUSTOMER_NAME": "My customer 2"
},
{ "ID": 5205039,
"CUSTOMER_ID": 1934806,
"CUSTOMER_NAME": "My customer 3"
}
]
';
INSERT INTO test
SELECT *
FROM JSON_TABLE(#data,
"$[*]" COLUMNS( ID INT PATH "$.ID",
CUSTOMER_ID INT PATH "$.CUSTOMER_ID",
CUSTOMER_NAME VARCHAR(255) PATH "$.CUSTOMER_NAME")
) AS jsontable;
SELECT * FROM test;
ID
CUSTOMER_ID
CUSTOMER_NAME
5464015
1088020
My customer 1
5220812
523323
My customer 2
5205039
1934806
My customer 3
db<>fiddle here
The solution which must work on 10.2.36-MariaDB (all used constructions are legal for this version):
CREATE TABLE test (ID INT, CUSTOMER_ID INT, CUSTOMER_NAME VARCHAR(255))
WITH RECURSIVE
cte1 AS ( SELECT LOAD_FILE('C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/json.txt') jsondata ),
cte2 AS ( SELECT 1 level, CAST(jsondata AS CHAR) oneobject, jsondata
FROM cte1
UNION ALL
SELECT level + 1,
TRIM(SUBSTRING(jsondata FROM 1 FOR 2 + LOCATE('}', jsondata))),
TRIM(SUBSTRING(jsondata FROM 1 + LOCATE('}', jsondata) FOR LENGTH(jsondata)))
FROM cte2
WHERE jsondata != '' )
SELECT oneobject->>"$.ID" ID,
oneobject->>"$.CUSTOMER_ID" CUSTOMER_ID,
oneobject->>"$.CUSTOMER_NAME" CUSTOMER_NAME
FROM cte2 WHERE level > 1;
Tested on MySQL 8.0.16 (I have no available MariaDB now):
The content of json.txt file matches shown in the question (misprint in attribute name edited).
PS. Of course the SELECT itself may be used for to insert the data into existing table.
If you have access to php a simple script is a good method, as it can turn json into an array (and automatically remove said quotes around text) and then you can decide what columns in the json equate to what mysql columns.
Depending on your mysql version you may have access to this utility to inport json from command line
https://mysqlserverteam.com/import-json-to-mysql-made-easy-with-the-mysql-shell/
But it may not work if your columns don't match perfectly with the MySQL columns ( I belieivd it is not case sensitive however )

How to return JSON property (SQL Server)

I am trying to select some data that is stored as JSON in SQL Server.
When I run isjson on the string, it returns 1.
However, I am unable to parse it.
declare #testStr nvarchar(max) = '{"order":{"address":{"shipToAddLine1":"1234 ABC Dr","shipToCityStZip":"Washington, DC 00000"}}}'
select isjson(#testStr) -- returns 1
select json_value(#testStr, '$'). -- returns null
select json_value(#testStr, '$.order') -- returns null
select #testStr -- returns entire string
How do I select the order node from the test string #testStr?
You can't use JSON_VALUE because that is not a scalar value, you need to use JSON_QUERY instead. An example of a scalar value would be the shipToAddLine1 field: select json_value(#testStr, '$.order.address.shipToAddLine1').
Using JSON_QUERY to get the order would be:
select json_query(#testStr, '$.order')
Result:
{"address":{"shipToAddLine1":"1234 ABC Dr","shipToCityStZip":"Washington, DC 00000"}}
You can use JSON_VALUE(), JSON_QUERY() and OPENJSON() to parse the input JSON. It's important to mention the following:
Function JSON_QUERY extracts an object or an array from a JSON string. If the value is not an object or an array, the result is NULL in lax mode and an error in strict mode.
Function JSON_VALUE extracts a scalar value from a JSON string. If the path points to not a scalar value, the result is NULL in lax mode and an error in strict mode
When you want to parse JSON string and get results as table, use OPENJSON table-valued function.
If you need to extract the order key you have two options - JSON_QUERY() or OPENJSON(). The following statement demonstrates how to extract a JSON object (from $.order key) and JSON values (from $.order.address.shipToAddLine1 and $.order.address.shipToCityStZip keys):
DECLARE #testStr nvarchar(max) =
N'{
"order":{
"address":{
"shipToAddLine1":"1234 ABC Dr",
"shipToCityStZip":"Washington, DC 00000"
}
}
}'
-- or
SELECT
shipToAddLine1 = JSON_VALUE(#testStr, '$.order.address.shipToAddLine1'),
shipToCityStZip = JSON_VALUE(#testStr, '$.order.address.shipToCityStZip'),
[order] = JSON_QUERY(#testStr, '$.order')
SELECT shipToAddLine1, shipToCityStZip, [order]
FROM OPENJSON(#testStr) WITH (
shipToAddLine1 nvarchar(100) '$.order.address.shipToAddLine1',
shipToCityStZip nvarchar(100) '$.order.address.shipToCityStZip' ,
[order] nvarchar(max) '$.order' AS JSON
)
Result:
shipToAddLine1 shipToCityStZip order
1234 ABC Dr Washington, DC 00000 {
"address":{
"shipToAddLine1":"1234 ABC Dr",
"shipToCityStZip":"Washington, DC 00000"
}
}