Dealing with special characters in SQL OPENJSON WITH command? - json

I have a JSON string that I am trying to import into my SQL Server database using the OPENJSON WITH but I am having issues because I think the JSON "field names" contain a forward slash.
What else would I need to do in order to get the start and end values? At the moment I just get NULLS...
DECLARE #JSONText NVarChar(max) = '[{
"Labour Resource Name": "ABC Consulting",
"Start Date/Time": "2020-07-06T06:30:00",
"End Date/Time": "2020-07-06T10:30:00"
}]'
SELECT *
FROM OPENJSON (#JSONText)
WITH ([Labour Resource Name] NVarChar(512),
[Start Date/Time] NVarChar(50),
[End Date/Time] NVarChar(50)
)

You don't have to mangle your output column aliases, instead you can specify JSON paths for all of them:
DECLARE #JSONText NVarChar(max) = '[{
"Labour Resource Name": "ABC Consulting",
"Start Date/Time": "2020-07-06T06:30:00",
"End Date/Time": "2020-07-06T10:30:00"
}]';
SELECT j.*
FROM OPENJSON (#JSONText)
WITH (
[LabourResourceName] nvarchar(512) '$."Labour Resource Name"',
[StartDateTime] nvarchar(50) '$."Start Date/Time"',
[EndDateTime] nvarchar(50) '$."End Date/Time"'
) j;

DECLARE #JSONText NVarChar(max) = '[{
"Labour Resource Name": "ABC Consulting",
"Start Date/Time": "2020-07-06T06:30:00",
"End Date/Time": "2020-07-06T10:30:00"
}]'
SELECT *
FROM OPENJSON (REPLACE(#JSONText, N'Date/Time', N'Date\/Time'))
WITH ([Labour Resource Name] NVarChar(512),
[Start Date/Time] NVarChar(50),
[End Date/Time] NVarChar(50)
)

Wrap the json field name in double quotes:
Before:
ecommerce nvarchar(max) '$.special-characters',
After:
ecommerce nvarchar(max) '$."special-characters"',

Related

How to read a complex json array with SQL Server

This is my query:
SELECT
JSON_QUERY(MyStringColumnWithJson, '$.Images') AS images
FROM MyTable
which returns a single field with the JSON data shown here below:
"{
"Images":
[
{"Name":"test1.jpeg","Description":"originalName1.jpeg"},
{"Name":"test2.jpeg","Description":"originalName2.jpeg"},
{"Name":"test3.jpeg","Description":"originalName3.jpeg"}
]
}"
How can I read the images result row by row into a temporary table structure?
Use OPENJSON which returns a data set, not JSON_VALUE, which returns a scalar value. For example:
DECLARE #JSON nvarchar(MAX) = N'{
"Images":
[
{"Name":"test1.jpeg","Description":"originalName1.jpeg"},
{"Name":"test2.jpeg","Description":"originalName2.jpeg"},
{"Name":"test3.jpeg","Description":"originalName3.jpeg"}
]
}';
SELECT *
FROM OPENJSON(#JSON, '$.Images')
WITH (Name nvarchar(128),
Description nvarchar(128))OJ;
SELECT I.[Name],
I.Description
FROM MyTable MT
CROSS APPLY OPENJSON(MT.YourJsonColumn, '$.Images')
WITH (Name nvarchar(128),
Description nvarchar(128)) I;

Discovery's Weird JSON, SQL Server, and OPENJSON

I am using an API from Discovery to extract some information from our virtual machines but the JSON for some reasons have the headings in one node and the values in another and they are in square brackets and I am having a hard getting to the end result.
This is a watered-down version of the JSON
DECLARE #JSON nvarchar(max) = N'[
{
"headings": [
"vm_type",
"Hostname"
],
"results": [
[
"AWS EC2 Instance",
null
],
[
"AWS EC2 Instance",
null
]
]
}
]'
SET #JSON = SUBSTRING(#JSON,2,LEN(#JSON) - 2)
SELECT *
FROM OPENJSON(#JSON)
SELECT *
FROM OPENJSON(#JSON,'$.results')
Is there a way to turn this into a table with the headings as column names and the results in the same order as its value?
You have an array of arrays, so this is effectively a dynamic pivot.
To do a dynamic pivot you need dynamic SQL. The easiest way to pivot is not usually to use PIVOT but to use conditional aggregation with MAX(CASE
DECLARE #sql nvarchar(max) = N'
SELECT
' + (
SELECT STRING_AGG(
QUOTENAME(j.value) + N' = MAX(CASE WHEN j2.[key] = ' + j.[key] + ' THEN j2.value END)',
',
') WITHIN GROUP (ORDER BY j.[key])
FROM OPENJSON(#JSON, '$[0].headings') j
) + '
FROM OPENJSON(#JSON, ''$[0].results'') j1
CROSS APPLY OPENJSON(j1.value) j2
GROUP BY
j1.[key];
';
PRINT #sql; --for testing
EXEC sp_executesql
#sql,
N'#JSON nvarchar(max)',
#JSON = #JSON;
db<>fiddle
Note correct use of QUOTENAME to quote column names, and use of sp_executesql with a parameter to pass in actual data, rather than injecting it directly into the query text.

How to insert date from JSON to SQL database

I have to insert some data from JSON to SQL database so I use below code:
sqlQuery1 = "DECLARE #json varchar(max)='" + inputData + "';";
sqlQuery2 = "INSERT INTO [Test].[dbo].[Work] " +
"SELECT [Id], [Created], [Assignee] " +
"FROM OPENJSON(#json) "+
"WITH ([Id] int '$.id',"+
"[Created] datetimeoffset(4) '$.fields.created',"+
"[Assignee] varchar(200) '$.fields.assignee.name')";
System.out.println(sqlQuery2); stmt.addBatch(sqlQuery1);stmt.addBatch(sqlQuery2); break;
$fields.created date has format eg: "2021-03-04T07:11:40.000+0000"
I tried using different way but not able to insert above format date into SQL.
Kindly help me with this code to insert created date to db.
Thank you in advance
SQL Server expects the time zone portion of your datetimeoffset string to include the colon character, i.e.: +00:00 instead of just +0000.
You will need to extract it from JSON as a varchar/nvarchar column first so that you can insert the : character before converting it to a datetimeoffset like so:
declare #json nvarchar(max) = N'{
"expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields",
"id": "180",
"fields": {
"created": "2021-03-04T07:11:40.000+0000",
"assignee": {
"name": "pallavi"
}
}
}';
select *
from openjson(#json) with (
[Id] int '$.id',
[Created] varchar(29) '$.fields.created',
[Assignee] varchar(200) '$.fields.assignee.name'
) shredded
outer apply (
select [CreatedDatetimeoffset] = convert(datetimeoffset, stuff(Created, 27, 0, ':'))
) converted;

How to read field name with space in Json using OPENJSON in SQL Server 2016

How can I read value from json file in that field name contains space using OPENJSON in Sql Server 2016. See the below code:
DECLARE #json NVARCHAR(MAX)
SET #json = N'{ "full name" : "Jayesh Tank"}';
SELECT * FROM OPENJSON(#json) WITH ( [name] [varchar](60) '$.full name')
Also another sample code in that space is after field name.
SET #json = N'{ "name " : "abc"}';
SELECT * FROM OPENJSON(#json) WITH ( [name] [varchar](60) '$.name')
'$.name' will return null.Is there way to read this value?
Generally it is a bad idea to use spaces in the attribute name.
I would leave out the [ ] from your OPENJSON name and varchar(60) - source MSDN OPENJSON.
Now to actually answer your question:
You need to format your attribute with double quotes in the WITH clause:
#DECLARE #json NVARCHAR(MAX);
SET #json=N'{ "full name" : "Jayesh Tank"}';
SELECT * FROM OPENJSON(#json) WITH (name varchar(60) '$."full name"')
for the second one:
SET #json = N'{ "name " : "abc"}';
SELECT * FROM OPENJSON(#json) WITH ( name varchar(60)'$."name "')
JSON_VALUE(c.value,'$.Serial Number') as [Serial Number] is throwing an error with a space. How do I resolve the space in the field name using JSON_VALUE .
by itself '$.Full Name' is not a valid json, but adding '$."Full Name"' the json becomes valid

SQL Server OPENJSON read nested json

I have some json that I would like to parse in SQL Server 2016. There is a hierarchy structure of Projects->Structures->Properties. I would like to write a query that parses the whole hierarchy but I don't want to specify any elements by index number ie I don't want to do anything like this:
openjson (#json, '$[0]')
or
openjson (#json, '$.structures[0]')
I had this idea that I could read the values of the top level project objects along with the json string that represents the structures below it, which could then be parsed separately. The problem is that the following code does not work:
declare #json nvarchar(max)
set #json = '
[
{
"IdProject":"97A76363-095D-4FAB-940E-9ED2722DBC47",
"Name":"Test Project",
"structures":[
{
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"IdProject":"97A76363-095D-4FAB-940E-9ED2722DBC47",
"Name":"Test Structure",
"BaseStructure":"Base Structure",
"DatabaseSchema":"dbo",
"properties":[
{
"IdProperty":"618DC40B-4D04-4BF8-B1E6-12E13DDE86F4",
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"Name":"Test Property 2",
"DataType":1,
"Precision":0,
"Scale":0,
"IsNullable":false,
"ObjectName":"Test Object",
"DefaultType":1,
"DefaultValue":""
},
{
"IdProperty":"FFF433EC-0BB5-41CD-8A71-B5F09B97C5FC",
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"Name":"Test Property 1",
"DataType":1,
"Precision":0,
"Scale":0,
"IsNullable":false,
"ObjectName":"Test Object",
"DefaultType":1,
"DefaultValue":""
}
]
}
]
}
]';
select IdProject, Name, structures
from openjson (#json)
with
(
IdProject uniqueidentifier,
Name nvarchar(100),
structures nvarchar(max)
) as Projects
IdProject and Name get returned no problem but for some reason I cannot get the nested json held in 'structures'. Instead of the json content it just returns NULL:
Does anyone know if this is possible and if so, what am I doing wrong?
Using CROSS APPLY:
declare #json nvarchar(max)
set #json = '
[
{
"IdProject":"97A76363-095D-4FAB-940E-9ED2722DBC47",
"Name":"Test Project",
"structures":[
{
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"IdProject":"97A76363-095D-4FAB-940E-9ED2722DBC47",
"Name":"Test Structure",
"BaseStructure":"Base Structure",
"DatabaseSchema":"dbo",
"properties":[
{
"IdProperty":"618DC40B-4D04-4BF8-B1E6-12E13DDE86F4",
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"Name":"Test Property 2",
"DataType":1,
"Precision":0,
"Scale":0,
"IsNullable":false,
"ObjectName":"Test Object",
"DefaultType":1,
"DefaultValue":""
},
{
"IdProperty":"FFF433EC-0BB5-41CD-8A71-B5F09B97C5FC",
"IdStructure":"CB0466F9-662F-412B-956A-7D164B5D358F",
"Name":"Test Property 1",
"DataType":1,
"Precision":0,
"Scale":0,
"IsNullable":false,
"ObjectName":"Test Object",
"DefaultType":1,
"DefaultValue":""
}
]
}
]
}
]';
select
Projects.IdProject, Projects.Name as NameProject,
Structures.IdStructure, Structures.Name as NameStructure, Structures.BaseStructure, Structures.DatabaseSchema,
Properties.*
from openjson (#json)
with
(
IdProject uniqueidentifier,
Name nvarchar(100),
structures nvarchar(max) as json
)
as Projects
cross apply openjson (Projects.structures)
with
(
IdStructure uniqueidentifier,
Name nvarchar(100),
BaseStructure nvarchar(100),
DatabaseSchema sysname,
properties nvarchar(max) as json
) as Structures
cross apply openjson (Structures.properties)
with
(
IdProperty uniqueidentifier,
NamePreoperty nvarchar(100) '$.Name',
DataType int,
[Precision] int,
[Scale] int,
IsNullable bit,
ObjectName nvarchar(100),
DefaultType int,
DefaultValue nvarchar(100)
)
as Properties
If you reference JSON object or array you need to specify AS JSON clause:
select IdProject, Name, structures
from openjson (#json)
with
(
IdProject uniqueidentifier,
Name nvarchar(100),
structures nvarchar(max) AS JSON
) as Projects
See FAQ: https://learn.microsoft.com/en-us/sql/relational-databases/json/solve-common-issues-with-json-in-sql-server?view=sql-server-ver15#return-a-nested-json-sub-object-from-json-text-with-openjson
If you want to apply OPENJSON on the returned structures array, you can use something like following code:
select IdProject, Name, structures
from openjson (#json)
with
(
IdProject uniqueidentifier,
Name nvarchar(100),
structures nvarchar(max) AS JSON
) as Projects
CROSS APPLY OPENJSON (structures) WITH (......)
Typical! I found the answer just after posting the question. You need to use the 'as json' key word when specifying the columns to return:
select IdProject, Name, structures
from openjson (#json)
with
(
IdProject uniqueidentifier,
Name nvarchar(100),
structures nvarchar(max) as json
) as Projects