Bulk insert of JSON arrays into SQL Server tables column separated - sql

How can I bulk insert JSON arrays into SQL Server 2016 tables with column separated without using JSON file (will get values with outer object from input)
Sample JSON can be found here

You can try [Not tested]:
[
{ "code" : 001,"name": "Prashant" },
{ "code" : 002,"name": "Steve" }
]
Query:
INSERT INTO your_table (code, name)
SELECT code,name
FROM OPENJSON(#json)
WITH (code int, name nvarchar(50))
To read from JSON object:
{"OUTER":{"ABC":"TEST_WB_New","XYZ":"9085"}} -- Your JSON
INSERT INTO your_table_name
SELECT ABC, XYZ
FROM OPENJSON(#json)
WITH (
ABC nvarchar(50) 'strict $.OUTER.ABC',
XYZ nvarchar(50) '$.OUTER.XYZ' AS JSON
)

Related

Conditional ON in a stored procedure with OPENJSON

I have this stored procedure that inserts data into a table from an API string that is passed to the OPENJSON function. This API though, sometimes renders a different key name according to the length of the value.
For instance:
{
{
"id":"1",
"shortName": Alex
},
"id":"2",
"longName": Alexander
}
}
Stored procedure:
CREATE PROCEDURE dbo.uspAddToTable
#json NVARCHAR(MAX)
AS
BEGIN
INSERT INTO dbo.MyTable (id, name)
SELECT id, name
FROM OPENJSON(#json)
WITH
(id integer '$.id',
name varchar(100) '$.shortName' /* here how do I do: OR '$.longName' if '$.shortName' does not exist */
) tbl
Is this possible in the stored procedure to take one or the other key value name depending if it can't find the default shortName to longName?
What you need to do, instead, is return both columns in your OPENJSON call, and then use COALESCE or ISNULL in your SELECT to return the non-NULL value:
CREATE PROCEDURE dbo.uspAddToTable #json nvarchar(MAX)
AS
BEGIN
INSERT INTO dbo.MyTable (id,name)
SELECT id,
ISNULL(shortName,longName)
FROM OPENJSON(#json)
WITH (id int,
shortName varchar(100),
longName varchar(100)) OJ;
END;
I assume here that one of the other will be NULL or that shortName is the "prioritised" value.

How to get data from json column in SQL Server that starts with array element

I have a database table that I need to extract data from where the column of interest has json it. What makes this particularly difficult is the most outer elements of the json is '[' & ']' as in the parent element is an array. I need to get the value associated with key 'Name' (which in this case is 'MS220'). However, I'm not able to path correctly to the key I want.
The below JData table is a duplicate copy of the data I need to perform the extract on. Between SELECT OPENJSON, JSON_VALUE, JSON_QUERY etc., how can I retrieve the value I'm looking for?
Below is a couple of selects I've tried but not quite getting it.
CREATE TABLE JData
(
JsonData nvarchar(max)
)
INSERT INTO JData (JsonData)
VALUES
('[
{
"Categories": [
{
"QuerySourceNames": [
"QAsset"
],
"Id": "eceae85a-ffc6-49f4-8f6a-78ce2b4b274e",
"Name": "emsdba"
}
],
"Id": "525b4f07-0f67-43ac-8070-a0e6c1ceb1b9",
"Name": "MS220"
}
]')
SELECT *
FROM OPENJSON (JData,'$.[0]')
WITH (
[Name] varchar(10) '$.Name'
)
SELECT
JSON_VALUE(JData,'$') as v
#AaronBertrand: I had to modify the answer a little since the table also has a column labeled [name] as well. Is there a way to UPDATE ParamName to a new value?
SELECT
t.[Name],
ParamName
FROM
[myDB].[dbo].[myTable] t
CROSS APPLY
OPENJSON (t.params)
WITH
(
Categories nvarchar(max) AS json,
Id uniqueidentifier,
ParamName varchar(10) '$.Name'
);
SELECT Name FROM dbo.JData
CROSS APPLY OPENJSON (JsonData)
WITH
(
Categories nvarchar(max) AS json,
Id uniqueidentifier,
[Name] varchar(10)
);
Example db<>fiddle

JSON_Query with For Json Path

Please see the table given below. The table contains the json string and need to create a json array with those json string. But When I use JSON_Query and For Json Path it adds additional header. (Alias name or the source column name). How to generate the json array without alias name or source column name.
Please see the example given below.
DECLARE #jsonTbl TABLE (id INT,json VARCHAR(MAX))
INSERT INTO #jsonTbl (id,json) VALUES (1,'{"id":"1A", "names":{"firstname":"Name1"}}')
INSERT INTO #jsonTbl (id,json) VALUES (1,'{"id":"2A", "names":{"firstname":"Name2"}}')
SELECT JSON_QUERY(json) AS 'someName'
FROM #jsonTbl
FOR JSON AUTO
--When I use the above select query it returns the data as
[{"SomeName":{"id":"1A", "names":{"firstname":"Name1"}}},{"SomeName":{"id":"2A", "names":
{"firstname":"Name2"}}}]
Formatted JSON
```[
{
"someName":{
"id":"1A",
"names":{"firstname":"Name1"}
}
},
{
"someName":{
"id":"1B",
"names":{
"firstname":"Name1"
}
}
}
]
--But need the result as follows. Do not need someName
[
{
"id":"1A",
"names":{
"firstname":"Name1"
}
},
{
"id":"2A",
"names":{
"firstname":"Name2"
}
}
]```
You can use OPENJSON() together with CROSS APPLY
SELECT j.[id], j.[names]
FROM #jsonTbl t
CROSS APPLY OPENJSON(t.json, '$') WITH ([id] VARCHAR(100),
[names] NVARCHAR(MAX) AS JSON) j
FOR JSON AUTO
Demo

Can I use FOR JSON without a source column name becoming a key in SQL Server 2016?

I have a table which contains json strings with a group id. I want to create a json array that contains all the json objects with the same id.
Note that in my case the column contents I'm trying to put into an array are json snippets themselves, therefore my case and question is more specific than turning rows into an array. The use of OPENJSON in the accepted answer also leverages this detail.
However, I could not find a way of using FOR JSON that allows me to select a single column without that column's name becoming the key for all the objects in the array.
I realise the key I'm trying to get rid of is necessary to project columns to keys of the key-value representation of json but in this case I'm selecting only one column and I'm curious if there is a trick I cannot think of.
I can achieve what I want by simply using COALASCE but I'd like to know if it is possible to handle this edge case using FOR JSON. Here is the simplified code that demonstrates what I'm trying to do:
BEGIN
declare #Json_Snippets table (id int, json nvarchar(max));
insert into #Json_Snippets (id, json) VALUES (1, '{"root":{"obj":"one"}}');
insert into #Json_Snippets (id, json) VALUES (1, '{"root":{"obj":"two"}}');
select
JSON_QUERY(js.json) as 'dont_want_this'
from
#Json_Snippets js
FOR JSON PATH;
END
I have to JSON_QUERY to avoid escaping characters in the json column, i.e. json string stays as json. Running the above gives:
[{"dont_want_this":{"root":{"obj":"one"}}},{"dont_want_this":{"root":{"obj":"two"}}}]
What I'd like to get is:
[{"root":{"obj":"one"}},{"root":{"obj":"two"}}]
If I understand you correctly, next approach may help. Just select your json data with OPENJSON() and WITH clause, then format the results with FOR JSON:
-- Table
declare #Json_Snippets table (id int, json nvarchar(max));
insert into #Json_Snippets (id, json) VALUES (1, '{"root":{"obj":"one"}}');
insert into #Json_Snippets (id, json) VALUES (1, '{"root":{"obj":"two"}}');
-- Statement
SELECT j.[root]
FROM #Json_Snippets t
CROSS APPLY OPENJSON(t.json, '$') WITH ([root] nvarchar(max) AS JSON) j
FOR JSON AUTO
Output:
[{"root":{"obj":"one"}},{"root":{"obj":"two"}}]
If you know the root key(s) you can use OPENJSON() WITH (... AS JSON) to extract their values as json and recreate json using FOR JSON. Here is an example:
DECLARE #json_snippets TABLE (id INT, json NVARCHAR(MAX));
INSERT INTO #json_snippets (id, json) VALUES
(1, '{"root":{"obj":"one"}}'),
(1, '{"root":{"obj":"two","foo":"bar"}}'),
(2, '{"root":{"obj":"three"}}');
SELECT id, (
SELECT j.*
FROM #json_snippets AS x
CROSS APPLY OPENJSON(json) WITH (
root NVARCHAR(MAX) AS JSON
) AS j
WHERE id = t.id
FOR JSON AUTO
)
FROM #json_snippets AS t
GROUP BY id
DECLARE #json_snippets TABLE (person INT, [json] NVARCHAR(MAX));
INSERT INTO #json_snippets (person, json) VALUES
(1, '{"obj":"one"}'),
(1, '{"obj":"two","foo":"bar"}'),
(2, '{"obj":"three"}');
SELECT x.person, JSON_QUERY('[' +x.sagg + ']') as objs
FROM (
SELECT w.person, STRING_AGG ([json], ',') as sagg
FROM #json_snippets as w
GROUP BY w.person
) as x
FOR JSON PATH
The result (with my best attempt at pretty-print):
[
{"person":1,"objs":[
{"obj":"one"}
,{"obj":"two","foo":"bar"}
]
}
,{"person":2,"objs":[
{"obj":"three"}
]
}
]

SQL Server: Update table based on JSON

I am trying to update rows in table based on JSON I have. JSON has the following structure:
"sensors": [
{
"id": "5afd7160f16819f11814f6e2",
"num": 0,
"name": "AC01",
"enabled": true,
"unit": "Volt AC Phase 1",
"desc": "NAMsdafE",
"lt_disaster": 1,
"gt_disaster": 1,
"lt_high": 1,
"gt_high": 1,
"lt_average": 1,
"gt_average": 1
},...
Table dbo.sensors has same structure + few more columns. To insert such JSON object, not array, into table, I would do it this way:
INSERT INTO dbo.sensors (.......)
SELECT .......
FROM OPENJSON(#json)
WITH (
id varchar(200),
....
);
So I have 2 questions: how to iterate over each element in JSON array and update each row with the same id. Any help would be appreciated:)
1) once you change the json into a select statement, you can iterate over that using cursor.
2) you can treat json select statement as a table. That said, you can do insert, update, delete operations exactly as you do with two tables. For updated case you can use code like this:
With Json_data as
( SELECT .......
FROM OPENJSON(#json)
WITH (
id varchar(200),
....
)
update S set ....
from dbo.sensors as S
inner join Json_data as JD on JD.id = S.id
First, read documentation OPENJSON. This feature is available starting version 2016.
Next, apply new knowledge.
--truncated for shortness
--note: wrap JSON string in curly brackets {}
declare #json nvarchar(max)='{"sensors":[
{
"id": "5afd7160f16819f11814f6e2",
"num": 0,
"name": "AC01",
"more": "unused"
},
{ "id": "5afd7160f16819f11814f6e3",
"num": 0,
"name": "AC02"
}]}
'
--insert...
select * from
openjson(#json,'$.sensors') --note the "path" argument here
with(
id varchar(200),
num int,
name varchar(10)
) json --alias sometimes required.
You can use result (rowset) as it is a table.
;With Json_data as
( SELECT
Evaluation_IDNO,
Rating_IDNO,
Notes_TEXT,
NextSteps_TEXT,
EvaluationCategory_CODE,
EvalType_ID
FROM OPENJSON(#As_EvaluationCategory_Json) WITH
(
Evaluation_IDNO INT N'$.matrixId',
Rating_IDNO VARCHAR(150) N'$.ratingValue',
Notes_TEXT VARCHAR(MAX) N'$.notesText',
NextSteps_TEXT VARCHAR(MAX) N'$.nextStepsText',
EvaluationCategory_CODE VARCHAR(50) N'$.ratingData',
EvalType_ID VARCHAR(4) N'$.evalTypeId'
)
AS EvaluationCategories
)
UPDATE EvaluationRatings_T1 SET
UserCreatedBy_ID=#As_SignedOnWorker_ID,
User_ID=#Ls_User_Id,
WorkspaceCreatedBy_ID=#Ls_WorkspaceCreatedBy_Id,
BeginValidity_DTTM=#Ls_Evaluation_DTTM,
EndValidity_DTTM=#Ld_HighValidity_DTTM,
TransactionEvenSeq_NUMB=#An_TransactionEventSeq_NUMB,
Update_DTTM=#Ld_BeginValiditiy_DTTM,
WorkspaceUpdatedBy_ID=#Ls_WorkspaceUpdatedBy_ID,
Evaluation_IDNO=c1.Evaluation_IDNO,
Rating_IDNO=c1.Rating_IDNO,
Notes_TEXT=c1.Notes_TEXT,
NextSteps_TEXT=c1.NextSteps_TEXT,
EvaluationCategory_CODE=c1.EvaluationCategory_CODE,
EvalType_ID=c1.EvalType_ID
FROM Json_data c1
inner JOIN EvaluationRatings_T1 e1 on e1.Evaluation_IDNO=c1.Evaluation_IDNO
WHERE e1.Evaluation_IDNO=#AS_Evaluation_IDNO;