Json input of a stored Procedure - sql

I have a Stored Procedure with a JSON in input ,Is it possible to use the JSON as input for a stored procedure? how could i do that ?
CREATE PROCEDURE [warm].[stored _table]
(
#Json NVARCHAR(MAX)
)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN
WITH JsonToTable AS
(
SELECT * FROM OPENJSON (#Json) WITH (
[type] [nvarchar](100),
[source] [nvarchar](38),
[time] [nvarchar](28),
[ID] [varchar](50) '$.data.ID',
[RegionCode] [varchar](10)'$.data.RegionCode'
[DueDate] [datetime2](7)'$.data.DueDate',
[SchedulStartDate] [datetime2](7)'$.data.SchedulStartDate',
)
)
MERGE [warm].[table] AS TARGET
USING JsonToTable AS SOURCE
ON (TARGET.ID = SOURCE.ID)
WHEN MATCHED THEN
UPDATE SET
TARGET.[RegionCode] = (SOURCE.[RegionCode]
TARGET.[DueDate] = [dbo].[ufn_cast_string_to_date](SOURCE.[DueDate])
,TARGET.[SchedulStartDate] = [dbo].[ufn_cast_string_to_date](SOURCE.[SchedulStartDate])
WHEN NOT MATCHED THEN
INSERT
(
[SourceID]
,[ID]
,[RegionCode]
,[DueDate]
,[SchedulStartDate])
VALUES
(
1
,[ID]
,[RegionCode]
,[dbo].[ufn_cast_string_to_date](SOURCE.[DueDate])
,[dbo].[ufn_cast_string_to_date](SOURCE.[SchedulStartDate])
);
END
END TRY
END
I Want to execute it with the request below :
DECLARE #return_value int
EXEC #return_value = [warm].[usp_upsert_warm_table]
#Json = N'{
"type" : "table",
"source" : "informations",
"time" : "2018-04-05T17:31:00Z",
"id" : "A11-111-111",
"data" : {"
"ID":"123-56",
"RegionCode":"2",
"DueDate":"2020-13-14T10:54:00",
"SchedulStartDate":"2020-12-14T10:54:00"
}'}
I get this Message Error :
JSON text is not properly formatted. Unexpected character '.' is found at position 480.**

This is the Valid input :
DECLARE #return_value int
EXEC #return_value = [warm].[usp_upsert_warm_table]
#Json = N'
{
"type" : "table1",
"source" : "",
"id" : "A111-111-11",
"time" : "2020-12-14 10:54:00",
"data" :{
"ApplicationID":"INFORMATIONS",
"ID":"157faf1657c-100",
"RegionCode":"2",
"DueDate":"2020-12-14 10:54:00",
"SchedulStartDate":"2020-12-14 10:54:00"}'}
For my input date : 2020-12-14 10:54:00 i deleteed the T in the middle
for my S.P : I change the type of My variables from datetime To varchar :
CREATE PROCEDURE [warm].[usp_upsert_warm_table]
...
[ID] [varchar](50) '$.data.ID',
[RegionCode] [varchar](10)'$.data.RegionCode'
[DueDate] [varchar](40)'$.data.DueDate',
[SchedulStartDate] [varchar](10)'$.data.SchedulStartDate',
....

Related

How to send Array of objects to stored procedure from nodejs express?

thanks in advance. Here i want to send a array of objects to the stored procedure via mssql connection to the ms sql-server from NodeJs backend. i have submitted my Stored Procedure and Backend code block.
--- Stored Procedure ---
CREATE PROCEDURE [dbo].[AddProductVariant]
#ProductId BIGINT ,
#Name NVARCHAR(200) ,
#InputTypeId TINYINT ,
#Attributes dbo.UT_ProductVariant READONLY
AS
BEGIN
BEGIN TRY
SET NOCOUNT ON;
DECLARE #Id BIGINT
INSERT INTO dbo.ProductVariants
( ProductId, Name, InputTypeId )
VALUES ( #ProductId -- ProductId - bigint
, #Name -- Name - nvarchar(50)
, #InputTypeId -- InputTypeId - tinyint
)
SET #Id = SCOPE_IDENTITY()
EXECUTE MergeProductVariantAttributes #Id, #Attributes
SELECT *
FROM SellEasyDb.dbo.ProductVariants
WHERE Id = #Id
--SELECT * FROM SellEasyDb.dbo.UserGroups WHERE SellEasyDb.dbo.UserGroups.Id = #Id
RETURN 0
END TRY
BEGIN CATCH
RETURN ##ERROR
END CATCH
END
--- NODE TS CODE ---
const pool = dbConnect.connect();
const request = dbConnect.request();
request.input("ProductId", req.body.productId);
request.input("Name", req.body.name);
request.input("InputTypeId", req.body.inputTypeId);
request.input("Attributes", req.body.attributes); // this is the array i want to send to SP
await request.execute("AddProductVariant", async (err: any, result: any, resultvalue: any) => {
debugger;
}
});
--- ERROR ---
class:16
code:'EREQUEST'
lineNumber:0
message:'Operand type clash: nvarchar is incompatible with UT_ProductVariant'
name:'RequestError'
number:206
state:2
--- User Define Type ---
CREATE TYPE UT_ProductVariant AS TABLE
(
[Id] [BIGINT],
[Title] [VARCHAR](200) NOT NULL,
[PriceAdjustment] [DECIMAL](18, 2) NOT NULL,
[IsDefault] [BIT] NOT NULL,
[SortOrder] [INT] NOT NULL,
[VarientId] [BIGINT],
[ProductId] [BIGINT]
)

SQL use return value of function as procedure parameter

Let's define:
create table cities
(
ID int identity,
name varchar(50) unique
)
create function getID (#name varchar(50)) returns int
begin
declare #id int
select #id=ID from cities where name=#name
return #id
end
create procedure addLine
#cityID int
as begin
...
end
Is it possible to execute a procedure with value returned by function, as follows?
exec addLine getID('Warsaw')
exec addLine dbo.getID('Warsaw')
exec addLine (select dbo.getID('Warsaw'))
I tried above and it did not help.
Microsoft says that this is not possible. You can not pass result of a function to procedure as a parameter:
[ { EXEC | EXECUTE } ]
{
...
[ [ #parameter = ] { value
| #variable [ OUTPUT ]
| [ DEFAULT ]
}
]
...
}
[;]
So, only constant values, variables and DEFAULT keyword are permitted.
2 possible ways of doing this are:
1: declare variable
declare #i int = dbo.getID('Warsaw')
exec addLine #i
2: use dynamic query
DECLARE #cmd NVARCHAR(MAX) = 'exec addLine ' + CAST(dbo.getID('Warsaw') AS NVARCHAR(MAX))
EXEC(#cmd)
This will "execute a procedure with value returned by function"
It just won't do it 'inline'
declare #id int
select #id = dbo.getID('Warsaw')
exec addLine #id

Comparing two nvarchar in a function

In a function I want to check whether passed value is equal to a predefined value (#ValX)
I have wrote following function:
ALTER Function IsNotInReview(#Val NVARCHAR(MAX))
RETURNS BIT
AS
BEGIN
DECLARE #ValX NVARCHAR(MAX)
SET #ValX = '
{
"httpCode" : 200,
"message" : "OK",
"result" : {
"items" : {
"items" : [ ]
}
}
}
'
IF LTRIM(RTRIM(#Val)) = LTRIM(RTRIM(#ValX))
BEGIN
RETURN 1
END
ELSE
BEGIN
RETURN 0
END
RETURN 0
END
When I test call the function, I am always getting false value
SELECT dbo.IsNotInReview('
{
"httpCode" : 200,
"message" : "OK",
"result" : {
"items" : {
"items" : [ ]
}
}
}
')--should return true
SELECT dbo.IsNotInReview('test')
UPDATE
I have updated my SP but still getting the same 'false' return value
ALTER Function IsNotInReview(#Val NVARCHAR(MAX))
RETURNS BIT
AS
BEGIN
DECLARE #ValX NVARCHAR(MAX)
SET #ValX = '
{
"httpCode" : 200,
"message" : "OK",
"result" : {
"items" : {
"items" : [ ]
}
}
}
'
DECLARE #ReturnVal BIT
IF LTRIM(RTRIM(#Val)) = LTRIM(RTRIM(#ValX))
BEGIN
SET #ReturnVal = 1
END
ELSE
BEGIN
SET #ReturnVal = 0
END
RETURN #ReturnVal
END
SELECT dbo.IsNotInReview('{
"httpCode" : 200,
"message" : "OK",
"result" : {
"items" : {
"items" : [ ]
}
}
}') --Return false which is unexpected
You are not comparing identical strings. Look at the indentation. I cannot imagine that this is what your intention is, i.e. comparing not only relevant content but also indentation.
A possible solution is to remove all white spaces, line breaks etc. in the string, while skipping over sections enclosed in double quotes.
Edit: Here is a little function which might be useful for you. It removes white spaces from your string while skipping quoted regions. Please test thoroughly, I only wrote it and testet it a bit (I have to go to work now)
create function RemoveWhiteSpaces (#String nvarchar(max))
returns nvarchar(max)
as
begin
declare #result nvarchar(max), #i int, #n int, #inQuotes bit,
declar #c0 nchar(1), #c nchar(1)
set #i=1
set #n=len(#string)
set #result=''
set #inQuotes=0
set #c='x'
while #i <= #n begin
set #c0=#c
set #c=substring(#string,#i,1)
if #c='"' and #c0 != '\'
set #inQuotes= 1 - #inQuotes
if #inQuotes = 1 or
(#inQuotes = 0 and #c not in (' ',char(13), char(10),char(8)))
set #result = #result + #c
set #i=#i+1
end
return #result
end

How to store the result of multiple SELECT statements in a stored procedure

I have a stored procedure where I need to run three separate SELECT statements and store the result in a variable.
I tried something like this:
SELECT #tier1MenuIds = Id
FROM TheGateKeeper.NavigationTier1
WHERE ([Page Name] = #currentSlug)
SELECT #tier2MenuIds = Id
FROM TheGateKeeper.NavigationTier2
WHERE ([Page Name] = #currentSlug)
SELECT #tier3MenuIds = Id
FROM TheGateKeeper.NavigationTier3
WHERE ([Page Name] = #currentSlug)
But it gives me an error saying
Incorrect syntax near '('.
The statement works if I remove the bottom two SELECTs. Any other options?
Edit: I am using SQL Server. Here is the full code:
CREATE PROCEDURE [TheGateKeeper].[editContent]
#description nvarchar(300),
#content nvarchar(MAX),
#title nvarchar(50),
#dateModified date,
#headerImageName nvarchar(100),
#slug nvarchar(50),
#id int
AS
BEGIN
SET NOCOUNT ON;
DECLARE #currentSlug as nvarchar(100);
DECLARE #tier1MenuIds as int;
DECLARE #tier2MenuIds as int;
DECLARE #tier3MenuIds as int;
/* Check if the post exists */
SELECT #currentSlug = Slug
FROM TheGateKeeper.Posts
WHERE (Id = #id)
IF (##ROWCOUNT = 1)
BEGIN
/* Temporarily unlink all menu items linking to post */
SELECT #tier1MenuIds = Id
FROM TheGateKeeper.NavigationTier1
WHERE ([Page Name] = #currentSlug)
SELECT #tier2MenuIds = Id
FROM TheGateKeeper.NavigationTier2
WHERE ([Page Name] = #currentSlug)
SELECT #tier3MenuIds = Id
FROM TheGateKeeper.NavigationTier3
WHERE ([Page Name] = #currentSlug)
/* Update the post in the database */
UPDATE Posts
SET (Description = #description, [Content] = #content, Title = #title, [Date Modified] =#dateModified, HeaderImageName = #headerImageName, slug =#slug)
WHERE id = #id
RETURN 1
END
ELSE
BEGIN
RETURN 0
END
Remove the parentheses from your UPDATE statement; they are unnecessary.
Your update statement should be:
UPDATE Posts
SET Description = #description, [Content] = #content, Title = #title,
[Date Modified] =#dateModified, HeaderImageName = #headerImageName,
slug =#slug
WHERE id = #id

how use replace in exec statement in sql server 2008

I have a stored proc, say, "call_Me" with few parameters:
Declare #Greet varchar(100) = 'Hi ||User||'
Exec Call_Me 1,'something', #Greet --parameters: bit, string, string
during the call, I want to be able to replace the
||User||
bit with something else. normally, in a select statement, I would do this:
select 1, 'something', Replace(#Greet, '||User||', u.Username) from UserTable
which works fine, But today, for the first time, I am trying to use it in exec statement, the error says its expecting select, I tried adding select in every possible (and sensible) way but it just didnt seem to work out.
How can I use a replace during an execute statement call?
Many thanks in advance!
You'd need to format #Greet before passing it to the sproc:
Declare #Greet varchar(100) = 'Hi ||User||'
SELECT #Greet = Replace(#Greet, '||User||', u.Username)
FROM UserTable u
WHERE Id = 1
Exec Call_Me 1,'something', #Greet --parameters: bit, string, string
You can only use a literal or a variable reference in a procedure call:
[ { EXEC | EXECUTE } ]
{
[ #return_status= ]
{ module_name [ ;number ] | #module_name_var }
[ [ #parameter= ] { value
| #variable [ OUTPUT ]
| [ DEFAULT ]
}
]
[ ,...n ]
[ WITH RECOMPILE ]
}
[;]
Use this:
Declare #Greet varchar(100) = 'Hi ||User||'
Declare #param VARCHAR(100) = REPLACE(#Greet, '||User||', 'replacement')
Exec Call_Me 1,'something', #param
I am not sure if I understand correctly your problem, but maybe using cursor solves your problem:
DECLARE CURSOR users LOCAL FAST_FORWARD FOR
SELECT
username
FROM
usertable
OPEN
DECLARE #username NVARCHAR(50)
DECLARE #Greet VARCHAR(100) = 'Hi ||User||'
FETCH NEXT FROM users INTO #username
WHILE ##FETCH_STATUS = 0 BEGIN
EXEC Call_Me 1, 'something', REPLACE(#Greet, '||User||', #username)
FETCH NEXT FROM users INTO #username
END
CLOSE users
DEALLOCATE users
If you don't need to call it in loop you can try something like (this can be a new stored procedure):
DECLARE #username NVARCHAR(50)
DECLARE #Greet VARCHAR(100) = 'Hi ||User||'
SELECT
#username = username
FROM
usernames
WHERE
user_id = 1
IF ##ROWCOUNT = 1 BEGIN
EXEC Call_Me 1, 'something', REPLACE(#Greet, '||User||', #username)
END