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

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]
)

Related

Json input of a stored Procedure

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',
....

make a variable default if something on sql server insert stament

i want to insert the default values, if the values i gave him are 0 or ''
ALTER procedure [dbo].[altaemp]
#id_emp int,
#nom_emp varchar(100),
#lnom_emp varchar(100),
#l2nom_emp varchar(100),
#id_type int,
#id_supervisor int,
#correo varchar(50),
#id_area int
as
begin
if #id_supervisor = 0 (select #id_supervisor = ?? )
if #correo = '' (select #correo = ??)
INSERT INTO [dbo].[empleados]
([id_emp]
,[nom_emp]
,[lnom_emp]
,[l2nom_emp]
,[id_type]
,[id_supervisor]
,[correo]
,[id_area])
VALUES
(#id_emp,
#nom_emp,
#lnom_emp,
#l2nom_emp,
#id_type,
#id_supervisor,
#correo,
#id_area)
return
end
i have tried equals the variables to null or default without success
To handle these 2 cases you can add the following decision statements, replacing ?? with your replacement value:
IF LEN(#correo) = 0 SET #correo = ??
IF #id_supervisor = 0 SET #id_supervisor = ??
I like to use a COALESCE with a NULLIF inside it to achieve this.
SELECT #id_supervisor = COALESCE(NULLIF(#id_supervisor,0),[DEFAULT VALUE])
,#correo = COALESCE(NULLIF(#correo ,' '),[DEFAULT VALUE])
There are multiple options for handling this scenario. If they are truly default values, you can simply pass null into the stored procedure and define the procedure like this:
ALTER procedure [dbo].[altaemp]
#id_emp int,
#nom_emp varchar(100),
#lnom_emp varchar(100),
#l2nom_emp varchar(100),
#id_type int,
#id_supervisor int = <default supervisor id>,
#correo varchar(50) = <default correo>,
#id_area int
as
begin
INSERT INTO [dbo].[empleados]
([id_emp]
,[nom_emp]
,[lnom_emp]
,[l2nom_emp]
,[id_type]
,[id_supervisor]
,[correo]
,[id_area])
VALUES
(#id_emp,
#nom_emp,
#lnom_emp,
#l2nom_emp,
#id_type,
#id_supervisor,
#correo,
#id_area)
return
end
Alternatively, if there is a decision that has to be made, you can replace your logic with case logic which would look similar to this:
ALTER procedure [dbo].[altaemp]
#id_emp int,
#nom_emp varchar(100),
#lnom_emp varchar(100),
#l2nom_emp varchar(100),
#id_type int,
#id_supervisor int = <default supervisor id>,
#correo varchar(50) = <default correo>,
#id_area int
as
begin
INSERT INTO [dbo].[empleados]
([id_emp]
,[nom_emp]
,[lnom_emp]
,[l2nom_emp]
,[id_type]
,[id_supervisor]
,[correo]
,[id_area])
Select #id_emp,
#nom_emp,
#lnom_emp,
#l2nom_emp,
#id_type,
CASE WHEN #id_supervisor = 0 THEN <Default SupervisorId> ELSE #id_supervisor END,
CASE WHEN #correo= '' THEN <Default correo> ELSE #correo END,
#id_area
return
end
Since you can pass null instead of 0 and '', then you can try this:
ALTER procedure [dbo].[altaemp]
#id_emp int,
#nom_emp varchar(100),
#lnom_emp varchar(100),
#l2nom_emp varchar(100),
#id_type int,
#id_supervisor int=100, -- Default value=100
#correo varchar(50)='my Default Value', -- Default Value
#id_area int
as
begin
INSERT INTO [dbo].[empleados]
([id_emp]
,[nom_emp]
,[lnom_emp]
,[l2nom_emp]
,[id_type]
,[id_supervisor]
,[correo]
,[id_area])
VALUES
(#id_emp,
#nom_emp,
#lnom_emp,
#l2nom_emp,
#id_type,
#id_supervisor,
#correo,
#id_area)
return
end
So, you can call the procedure like this:
EXEC [dbo].[altaemp]
#id_emp = yourValue,
#nom_emp = yourValue,
#lnom_emp = yourValue,
#l2nom_emp = yourValue,
#id_type = yourValue,
#id_supervisor = null, -- Specify Null or remove parameter
#correo = null, -- Specify Null or remove parameter
#id_area = yourValue

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

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 to get a distinct list of words used in all Field Records using MS SQL?

If I have a table field named 'description', what would be the SQL (using MS SQL) to get a list of records of all distinct words used in this field.
For example:
If the table contains the following for the 'description' field:
Record1 "The dog jumped over the fence."
Record2 "The giant tripped on the fence."
...
The SQL record output would be:
"The","giant","dog","jumped","tripped","on","over","fence"
I do not think you can do this with a SELECT. The best chance is to write a user defined function that returns a table with all the words and then do SELECT DISTINCT on it.
Disclaimer: Function dbo.Split is from http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=50648
CREATE TABLE test
(
id int identity(1, 1) not null,
description varchar(50) not null
)
INSERT INTO test VALUES('The dog jumped over the fence')
INSERT INTO test VALUES('The giant tripped on the fence')
CREATE FUNCTION dbo.Split
(
#RowData nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
While (Charindex(#SplitOn,#RowData)>0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END
CREATE FUNCTION dbo.SplitAll(#SplitOn nvarchar(5))
RETURNS #RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
DECLARE My_Cursor CURSOR FOR SELECT Description FROM dbo.test
DECLARE #description varchar(50)
OPEN My_Cursor
FETCH NEXT FROM My_Cursor INTO #description
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #RtnValue
SELECT Data FROM dbo.Split(#description, #SplitOn)
FETCH NEXT FROM My_Cursor INTO #description
END
CLOSE My_Cursor
DEALLOCATE My_Cursor
RETURN
END
SELECT DISTINCT Data FROM dbo.SplitAll(N' ')
I just had a similar problem and tried using SQL CLR to solve it. Might be handy to someone
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.Collections.Generic;
public partial class UserDefinedFunctions
{
private class SplitStrings : IEnumerable
{
private List<string> splits;
public SplitStrings(string toSplit, string splitOn)
{
splits = new List<string>();
// nothing, return empty list
if (string.IsNullOrEmpty(toSplit))
{
return;
}
// return one word
if (string.IsNullOrEmpty(splitOn))
{
splits.Add(toSplit);
return;
}
splits.AddRange(
toSplit.Split(new string[] { splitOn }, StringSplitOptions.RemoveEmptyEntries)
);
}
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
return splits.GetEnumerator();
}
#endregion
}
[Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName = "readRow", TableDefinition = "word nvarchar(255)")]
public static IEnumerable fnc_clr_split_string(string toSplit, string splitOn)
{
return new SplitStrings(toSplit, splitOn);
}
public static void readRow(object inWord, out SqlString word)
{
string w = (string)inWord;
if (string.IsNullOrEmpty(w))
{
word = string.Empty;
return;
}
if (w.Length > 255)
{
w = w.Substring(0, 254);
}
word = w;
}
};
It is not the fastest approach but might be used by somebody for a small amount of data:
declare #tmp table(descr varchar(400))
insert into #tmp
select 'The dog jumped over the fence.'
union select 'The giant tripped on the fence.'
/* the actual doing starts here */
update #tmp
set descr = replace(descr, '.', '') --get rid of dots in the ends of sentences.
declare #xml xml
set #xml = '<c>' + replace(
(select ' ' + descr
from #tmp
for xml path('')
), ' ', '</c><c>') + '</c>'
;with
allWords as (
select section.Cols.value('.', 'varchar(250)') words
from #xml.nodes('/c') section(Cols)
)
select words
from allWords
where ltrim(rtrim(words)) <> ''
group by words
In SQL on it's own it would probably need to be a big stored procedure, but if you read all the records out to the scripting language of your choice, you can easily loop over them and split each out into arrays/hashes.
it'd be a messy stored procedure with a temp table and a SELECT DISTINCT at the end.
if you had the words already as records, you would use SELECT DISTINCT [WordsField] from [owner].[tablename]