the name is not a valid identifier. error in dynamic stored procudure - sql

my stored procudure is :
ALTER PROCEDURE [dbo].[Asbabbazi_A]
#name_product nvarchar(50),
#first_price int,
#final_price int,
#collection_1 nvarchar(30),
#id_state tinyint
AS
BEGIN
DECLARE #SQLstring nvarchar(1000)
DECLARE #PARAMS nvarchar(1000)
set #SQLstring = 'SELECT IDproduct,name_product,first_price,final_price,max_registered_price,
date_record_shamsi,final_date_view_shamsi,
count_views,image_1,collection_1 from Table_asbabbazi where active=0 '
if(#name_product != 'no name')
set #SQLstring = #SQLstring + ' AND (name_product LIKE %#name_product%)'
if (#final_price != 0)
set #SQLstring = #SQLstring + ' AND ( first_price between #first_price AND #final_price )'
if (#collection_1 != 'انتخاب کنید')
set #SQLstring = #SQLstring + ' AND (collection_1 = #collection_1 )'
if (#id_state != 0)
set #SQLstring = #SQLstring + ' AND (id_state = #id_state )'
execute #SQLstring
END
when execute show this error:
The name 'SELECT IDproduct,name_product,first_price,final_price,max_registered_price,
date_record_shamsi,final_date_view_shamsi,
count_views,image_1,collection_1 from Table_asbabbazi where active=0 AND (name_product LIKE %#name_product%) AND (collection_1 = #collection_1 )' is not a valid identifier.
please help

Some parameters in a query string are not parsed correctly, and you are using dynamic sql it must be executed by EXECUTE sp_executesql statement. This is the correct way to execute dynamic sql:
ALTER PROCEDURE [dbo].[Asbabbazi_A]
#name_product nvarchar(50),
#first_price int,
#final_price int,
#collection_1 nvarchar(30),
#id_state tinyint
AS
BEGIN
DECLARE #SQLstring nvarchar(1000)
DECLARE #PARAMS nvarchar(1000)
set #SQLstring = 'SELECT IDproduct,name_product,first_price,final_price,max_registered_price,
date_record_shamsi,final_date_view_shamsi,
count_views,image_1,collection_1 from Table_asbabbazi where active=0 '
if(#name_product != 'no name')
set #SQLstring = #SQLstring + ' AND name_product LIKE ''%' + #name_product + '%''' + ' '
if (#final_price != 0)
set #SQLstring = #SQLstring + ' AND first_price between ' + CONVERT(nvarchar(1000), #first_price) + ' AND ' + CONVERT(nvarchar(1000), #final_price) + ' '
if (#collection_1 != 'انتخاب کنید')
set #SQLstring = #SQLstring + ' AND collection_1 = ''' + #collection_1 + ''' '
if (#id_state != 0)
set #SQLstring = #SQLstring + ' AND id_state = ' + CONVERT(nvarchar(1000), #id_state) + ' '
EXECUTE sp_executesql #SQLstring
END

In brief,
put declared SQLstring inside Parenthesis when execute stored procedure like this
👉 EXECUTE usp_executeSql (#SQLstring)
Example:
False ❌
EXECUTE usp_executeSql #SQLstring
True ✔
EXECUTE usp_executeSql (#SQLstring)

You have your variables inside quotes thus making them string literals. Instead of this sort of thing:
set #SQLstring = #SQLstring + ' AND (collection_1 = #collection_1 )'
you need this sort of thing:
set #SQLstring = #SQLstring + ' AND (collection_1 = '
+ #collection_1 + ' )'

Related

how to create a dynamic update query with variables?

I am trying to create the below dynamic update query with some variables and for some reason, it's not working inside the stored procedure. Can someone suggest to me where I am doing wrong and what's the best practice by avoiding the SQL Injection as well?
DECLARE #SQL NVARCHAR(MAX)
DECLARE #COLUMN1 NVARCHAR(10)
DECLARE #COLUMN2 NVARCHAR(10)
DECLARE #TABLENAME NVARCHAR(10)
SET #SQL = 'UPDATE TL
SET '+ #COLUMN1 + '= AB.COLUMN1,'
+ #COLUMN2 + '= AB.COLUMN2
FROM' + #TABLENAME + ' TL
JOIN ABACUS AB
ON TL.REF = AB.REF
AND TL.SUBS = AB.SUBS
WHERE ' + #COLUMN1 + ' IS NULL
AND ' + #COLUMN2 +' IS NULL';
SET #COLUMN1 = (SELECT CONCAT('USER_ID', '8'))
SET #COLUMN2 = (SELECT CONCAT('USER_ID', '6'))
SET #TABLENAME = 'POLICYREF';
EXEC sys.sp_executesql #SQL, #TABLENAME, #COLUMN1, #COLUMN2;
SET #TABLENAME = 'USERREF';
EXEC sys.sp_executesql #SQL, #TABLENAME, #COLUMN1, #COLUMN2;
You need dynamic SQL, not parameters. You can't parameterize column names or table names. So something like:
DECLARE #SQL NVARCHAR(MAX)
DECLARE #COLUMN1 NVARCHAR(10) = 'USER_ID8'
DECLARE #COLUMN2 NVARCHAR(10) = 'USER_ID6'
DECLARE #TABLENAME NVARCHAR(10) = 'POLICYREF'
SET #SQL = 'UPDATE TL
SET '+ quotename(#COLUMN1) + '= AB.COLUMN1,'
+ quotename(#COLUMN2) + '= AB.COLUMN2
FROM ' + quotename(#TABLENAME) + ' TL
JOIN ABACUS AB
ON TL.REF = AB.REF
AND TL.SUBS = AB.SUBS
WHERE ' + quotename(#COLUMN1) + ' IS NULL
AND ' + quotename(#COLUMN2) +' IS NULL';
EXEC (#SQL)
SET #TABLENAME NVARCHAR(10) = 'USERREF'
SET #SQL = 'UPDATE TL
SET '+ quotename(#COLUMN1) + '= AB.COLUMN1,'
+ quotename(#COLUMN2) + '= AB.COLUMN2
FROM ' + quotename(#TABLENAME) + ' TL
JOIN ABACUS AB
ON TL.REF = AB.REF
AND TL.SUBS = AB.SUBS
WHERE ' + quotename(#COLUMN1) + ' IS NULL
AND ' + quotename(#COLUMN2) +' IS NULL';
EXEC (#SQL)
Not a huge fan of this but, given that, create a stored procedure OR re-arrange to execute each after updating the #SQL, here is the stored procedure example:
Note this is missing production level things like a transaction, TRY CATCH etc. and is only for an basic UNTESTED example
CREATE PROCEDURE dbo.MyFunQuery
#SQL NVARCHAR(MAX),
#COLUMN1 NVARCHAR(10),
#COLUMN2 NVARCHAR(10),
#TABLENAME NVARCHAR(10)
AS
BEGIN
SET #SQL = 'UPDATE TL
SET '+ #COLUMN1 + '= AB.COLUMN1,'
+ #COLUMN2 + '= AB.COLUMN2
FROM ' + #TABLENAME + ' AS TL
JOIN ABACUS AS AB
ON TL.REF = AB.REF
AND TL.SUBS = AB.SUBS
WHERE ' + #COLUMN1 + ' IS NULL
AND ' + #COLUMN2 + ' IS NULL;';
EXECUTE ( #SQL );
END
--Now to call it:
DECLARE #COLUMN1 NVARCHAR(10) = 'USER_ID8',
#COLUMN2 NVARCHAR(10) = 'USER_ID6';
EXECUTE dbo.MyFunQuery #COLUMN1, #COLUMN2, #TABLENAME='POLICYREF';
EXECUTE dbo.MyFunQuery #COLUMN1, #COLUMN2, #TABLENAME='USERREF';

How to pass Server Name dynamically in SQL Server

SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX),
#servername NVARCHAR(255)
SET #servername = '[s-printstream]'
--Drop Table #Actual
CREATE TABLE #Actual
(
jobnumber INT,
firstNameCounts VARCHAR(25),
lastNameCounts VARCHAR(25),
address1Counts VARCHAR(25),
address2Counts VARCHAR(25),
cityCounts VARCHAR(25),
stateCounts VARCHAR(25),
zipCounts VARCHAR(25),
inHomeDateCounts VARCHAR(25)
)
SET #sql = 'INSERT INTO #actual (jobnumber,firstNameCounts,lastNameCounts , address1Counts, address2Counts, cityCounts, stateCounts, zipCounts, inHomeDateCounts) '
SET #sql = #sql + ' Select s.jobnumber, count(s.firstName) AS [firstNameCounts], Count (s.lastName) AS [lastNameCounts], Count (s.Address1) As [address1Counts], Count (s.address2)-Count (address2) AS '
SET #sql = #sql + ' [address2Counts], Count (s.City) AS [cityCounts], Count (s.State) AS [stateCounts], Count (s.Zip) AS [zipCounts], Count (jb.inHomeDate) AS [inHomeDateCounts] '
SET #sql = #sql + ' From' + ' #servername ' + '.[tdis_417133]' + '.[dbo].[tblStandardFinal] s '
SET #sql = #sql + ' INNER JOIN [s-printstream].[tdSchedule2].[dbo].[tblJobTicketActions] jb '
SET #sql = #sql + ' ON jb.psFlagJobNumber = s.jobNumber '
SET #sql = #sql + ' where jobNumber = #jobNumber '
SET #sql = #sql + ' group by jobNumber '
PRINT #SQL
EXEC sp_executesql #sql
,N'#JobNumber Varchar(25)'
,#JobNumber = 417133
Could anyone please help me find out how I would pass my server name dynamically as well as the database name? When I try to do it, I get this error:
Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "#servername"
Any help is appreciated.
Thanks
or pass #servername value into sql command
EXEC sp_executesql #sql
,N'#JobNumber Varchar(25),#servername nvarchar(255)'
,#JobNumber = 417133,#servername=#servername

sp_executesql returns nothing when parameter is null

I've got this piece of code in my procedure:
SET #Sql = 'SELECT #Value = ' + #Column + ' FROM #inserted'
exec sp_executesql #Sql, N'#Value varchar(MAX) out', #NEW out
SET #Sql = 'SELECT #Value = ' + #Column + ' FROM #deleted'
exec sp_executesql #Sql, N'#Value varchar(MAX) out', #OLD out
And when the column value is null the variable #OLDdoesn't have nothing and for some reason when I compare the 2 variables:
IF #NEW != #OLD
It doesn't get inside the IF, even if the #OLD is empty and #NEW isn't. I've tried this:
IF #OLD is null or datalength(#OLD)=0 or #NEW != #OLD
But still no good result. When I print the 2 variables the #OLD doesn't print anything (in the cases where is null in the table).
Can you help me?
Thank you :)
EDIT
This is a trigger that I built for some tables in my database when they're updated so I can save the changes made. To make it easy I created a loop trough the columns name of that table and for every column I do that piece of code that its giving me problems. Here's a bit more of my trigger:
WHILE(#LoopCounter <= #MAX)
BEGIN
SELECT #Column = COLUMN_NAME, #Type = DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS WHERE ORDINAL_POSITION = #LoopCounter and TABLE_NAME = 'Parameters'
SET #Sql = 'SELECT #Value = ' + #Column + ' FROM #inserted'
exec sp_executesql #Sql, N'#Value varchar(MAX) out', #NEW out
SET #Sql = 'SELECT #Value = ' + #Column + ' FROM #deleted'
exec sp_executesql #Sql, N'#Value varchar(MAX) out', #OLD out
IF #OLD is null or datalength(#OLD)=0 or #NEW != #OLD
BEGIN
/* some code */
END
SET #LoopCounter = #LoopCounter + 1
END
So check null states:
IF #NEW != #OLD
OR #NEW IS NULL AND #OLD IS NOT NULL
OR #OLD IS NULL AND #NEW IS NOT NULL
BEGIN
...
Why not go proactive...don't execute if your #Column is null..
WHILE(#LoopCounter <= #MAX)
BEGIN
SELECT #Column = COLUMN_NAME, #Type = DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS WHERE ORDINAL_POSITION = #LoopCounter and TABLE_NAME = 'Parameters'
IF ISNULL(#Column,'')<>''
BEGIN
SET #Sql = 'SELECT #Value = ' + #Column + ' FROM #inserted'
exec sp_executesql #Sql, N'#Value varchar(MAX) out', #NEW out
SET #Sql = 'SELECT #Value = ' + #Column + ' FROM #deleted'
exec sp_executesql #Sql, N'#Value varchar(MAX) out', #OLD out
IF #OLD is null or datalength(#OLD)=0 or #NEW != #OLD
BEGIN
/* some code */
END
END
SET #LoopCounter = #LoopCounter + 1
END
Ok, I found a solution. Thank you for your tips. I changed my code to:
SET #Sql = 'SELECT #Value = ' + #Column + ' FROM #inserted'
exec sp_executesql #Sql, N'#Value varchar(MAX) out', #NEW out
SET #Sql = 'SELECT #Value = ' + #Column + ' FROM #deleted'
exec sp_executesql #Sql, N'#Value varchar(MAX) out', #OLD out
IF ISNULL(#NEW,0) != ISNULL(#OLD,0)
With ISNULLeverything goes ok. I've also had to use this in another place in my code where I was concatenating a stringwith the #OLDand #NEW values.
Thank you :)

SQL Server dynamic procedure 2

USE KronosNET22
GO
Create procedure eventossucursales4
#id nvarchar(max),
#dia nvarchar(max)
as
begin
declare #sqlstring nvarchar(max)
set #sqlstring = 'Select Code From ' + #dia + ' WHERE idObject = ''' + #id + ''' AND (CODE = ''TFHi2'' OR CODE = ''E603'')'
EXEC sp_executesql #sqlstring, #id,#dia
end
GO
Execute eventossucursales4 'E4211537-09CD-45F2-BB5F-F20F642DE676','ObjectSignal_2016_05_23 '
Error:
Mens. 102, Nivel 15, Estado 1, Línea 1
Sintaxis incorrecta cerca de 'E4211537'.
Can someone help me to figure it out why its showing a mistake in the declaration of the variable?
You could eliminate passing the parameters as someone commented. If you want to make it work as is, you need to add the parameter list. I was able to get it working this way.
alter procedure eventossucursales4
#id nvarchar(max),
#dia nvarchar(max)
as begin
declare #sqlstring nvarchar(max)
declare #ParmDefinition nvarchar(500) = '#dia nvarchar(max), #id nvarchar(max)'
set #sqlstring = 'Select Code From ' + #dia + ' WHERE idObject = ''' + #id + ''' AND (CODE = ''TFHi2'' OR CODE = ''E603'')'
exec sp_executesql #sqlstring, #ParmDefinition, #id = #id, #dia = #dia
end
GO
Execute eventossucursales4 'E4211537-09CD-45F2-BB5F-F20F642DE676','ObjectSignal_2016_05_23 '

How to pass datetime in dynamic query in sql?

I have written a stored procedure like this
ALTER PROCEDURE [dbo].[spLoadPendingPaymentSheetByFilter] --'2015-04-01','2015-04-02','Select-One','Select-One','Select-One',''
#FromDate as datetime,
#ToDate as datetime,
#Status as nvarchar(50),
#Remarks as nvarchar(50),
#Paymenttype as nvarchar(50),
#BillID as nvarchar(50)
AS
Declare #Where as nvarchar(max)
set #Where = '( MenifestDate BETWEEN ''' + CONVERT(VARCHAR(10),#FromDate, 101) + ''' and ''' + CONVERT(VARCHAR(10),#ToDate, 101) + ''' )'
if(#Status <> 'Select-One')
set #Where = 'Status = '+ #Status
if(#Remarks <> 'Select-One')
set #Where = #Where + 'and Remarks = '+ #Remarks
if(#Paymenttype <> 'Select-One')
set #Where = #Where + 'and PaymentType = ' + #Paymenttype
if(#BillID <> '')
set #Where = #Where + 'and BillID = '+ #BillID
Declare #SelectString as nvarchar(1000)
set #SelectString = 'SELECT MasterID,BillID, MenifestDate, FarwardingNo,ReceverCountryName,Status,Remarks,PaymentType
FROM tblMenifest
WHERE ' + #Where
exec #SelectString
When I execute it I got this error
The name 'SELECT MasterID,BillID, MenifestDate, FarwardingNo,ReceverCountryName,Status,Remarks,PaymentType FROM tblMenifest WHERE ( MenifestDate BETWEEN '04/01/2015' and '04/02/2015' )' is not a valid identifier
The MenifestDate column datatype is datetime.
I believe that you want to put EXEC(#SelectString) rather than exec #SelectString.