utilize ident_current in JSON insert - sql

Is it possible to merge / mix / join the SQL command IDENT_CURRENT('table_name') with a OPENJSON insert statement?
For example a table dbo.properties contains:
id as int (primary key, auto increment)
objectId as int
property as varchar(50)
value as varchar (50)
I fill the property and value based on a JSON and are in need to use IDENT_CURRENT('objects') to fill the objectId column. Currently my statement looks like:
DECLARE #properties nvarchar(max) = N'[{"property": "A", "value": "1"},
{"property": "B", "value": "2"},
{"property": "C", "value": "3"}]';
INSERT INTO dbo.property
SELECT *
FROM OPENJSON(#properties)
WITH ( property varchar(50) '$.property',
value varchar(50) '$.value');
And want to change the statement to something like:
DECLARE #properties nvarchar(max) = N'[{"property": "A", "value": "1"},
{"property": "B", "value": "2"},
{"property": "C", "value": "3"}]';
INSERT INTO dbo.property (objectId)
VALUES (IDENT_CURRENT('nodes'))
SELECT *
FROM OPENJSON(#properties)
WITH ( property varchar(50) '$.property',
value varchar(50) '$.value');

Cannot say I'd necessarily recommend your approach. Generally I'd recommend inserting into both tables together and using SCOPE_IDENTITY() instead. With your approach, if another process inserts a row at the same time, it could cause data issues since your script might grab the wrong identity value
DECLARE #id INT;
BEGIN TRAN
/*
INSERT INTO nodes...
Put your code here that inserts into the nodes table */
SELECT #id = SCOPE_IDENTITY() /*Returns last IDENTITY inserted into nodes. RECOMMEND THIS APPROACH*/
--SELECT #id =IDENT_CURRENT('nodes') /*Using your requested function*/
INSERT INTO property(objectid,property,[value])
SELECT #id,property,[value]
FROM OPENJSON(#properties)
WITH ( property varchar(50) '$.property',
value varchar(50) '$.value');
COMMIT TRAN

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

Insert data into a table using OPENJson

I have the following Json that needs to be inserted into a table
{"errorMessage":"","requestOutput":{ "REQUEST_ID" : 100910, "STATUS_CODE" : "P", "PHASE_CODE" :
"N", "COMPLETION_TEXT" : null }}
This is the query i am using to process the json and insert into the table
INSERT INTO dbo.tblRequest_Details([RequestId]
,[Error_Message]
,[Status_Code]
,[Phase_Code]
,[Completion_Text])
SELECT [RequestId]
,[Error_Message]
,[Status_Code]
,[Phase_Code]
,[Completion_Text]
FROM OPENJSON((select * from #json2), N'$.requestOutput')
WITH (
[RequestId] nvarchar(max) N'$.REQUEST_ID',
[Status_Code] nvarchar(max) N'$.STATUS_CODE',
[Phase_Code] nvarchar(max) N'$.PHASE_CODE',
[Completion_Text] nvarchar(max) N'$.COMPLETION_TEXT')
CROSS APPLY OPENJSON((select * from #json2), N'$.errorMessage')
WITH( [Error_Message] nvarchar(max) N'$.errorMessage'
)
But for some reason, data does not get inserted into the table.
What am I doing wrong?
Thanks
Turns out there was an error with the errorMessage field so I removed the cross apply. Instead assigned the value of errorMessage to a variable and used that instead.

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;

SQL Merge Statement - Output into a scalar variable (SQL Server)

I'm getting my head around the MERGE statement in SQL server. I generally use it to insert/update a single row, which I realise isn't the only use, but it's something I seem to do quite often.
But what happens if you want to insert a value of 1, or update to increment the value and output the incremented value eg:
CREATE TABLE [Counter] (
[Key] VARCHAR(255) NOT NULL PRIMARY KEY,
[Value] INT NOT NULL
);
DECLARE #paramKey VARCHAR(255);
SET #paramKey = 'String';
MERGE [Counter] AS targt
USING (Values(#paramKey)) AS source ([Key])
ON (targt.[Key] = source.[Key])
WHEN MATCHED THEN
UPDATE SET Value = Value +1
WHEN NOT MATCHED THEN
INSERT ([Key], Value)
VALUES (source.[Key], 1);
-- but now I want the new value!
Is there a way of doing this? I notice the output clause in https://msdn.microsoft.com/en-gb/library/bb510625.aspx but it doesn't seem to work with scalars (I could output to a single row-ed table variable but that seems wrong):
-- using table variables but seems
DECLARE #paramKey VARCHAR(255), #value int;
SET #paramKey = 'String'
DECLARE #Tab table (
[Value] INT
)
MERGE Counter AS targt
USING (Values(#paramKey)) AS source ([Key])
ON (targt.[Key] = source.[Key])
WHEN MATCHED THEN
UPDATE SET Value = Value +1
WHEN NOT MATCHED THEN
INSERT ([Key], Value)
VALUES (source.[Key], 1)
OUTPUT inserted.[Value] INTO #Tab;
-- can now use #Tab as a single rowed table variable
Is there a better option?