Pass date parameter to dynamic sql - sql

I'm having a very hard time framing this query. The error is - Conversion failed when converting date from character string.
It is a generic query to work for all tables. All was working good, but i had to add a date parameter.
SQL:
DECLARE #qryUpd nvarchar(MAX), #params nvarchar(MAX), #TableName nvarchar(50),
#ColName nvarchar(50),#Id nvarchar(50),#ModifiedBy nvarchar(50),
#ModifiedDate datetime
set #qry = 'update '+#TableName+' set Deleted=1, ModifiedBy='+''''+#Id+''',
ModifiedDate='+''''+#ModifiedDate+''''+' where '+#Colname+'='+''''+
#Id+''''
execute sp_executesql #qry
C#:
public void test(int id, int userid)
{
sqlCommand cmd = new sqlcommand("TestFunc",con);
cmd.commandtype = commandtype.storedprocedure;
cmd.parameters.addwithvalue("#TableName","tblArea");
cmd.parameters.addwithvalue("#ColName","AreaId");
cmd.parameters.addwithvalue("#Id",id);
cmd.parameters.addwithvalue("#ModifiedBy",userid);
cmd.parameters.addwithvalue("#ModifiedDate",system.datetime.now.tostring());
}

With the exception of the dynamic table name and the column, you can at least partially parameterize your query, which will take away the headache of escaping quotes, and also give some protection against Sql Injection (since the table and column are still vulnerable and need to be validated):
DECLARE #qry AS NVARCHAR(MAX);
set #qry = N'update '+#TableName +
' set Deleted=1, ModifiedBy=#ModifiedBy, ModifiedDate=#ModifiedDate
where ' + #Colname + ' = #Id';
exec sp_executesql #qry,
N'#Id nvarchar(50), #ModifiedBy nvarchar(50), #ModifiedDate datetime',
#Id = #Id,
#ModifiedBy = #ModifiedBy,
#ModifiedDate = #ModifiedDate;
SqlFiddle here
You can then bind your .Net parameters for #Id, #ModifiedBy and #ModifiedDate directly with the native types

You are passing the parameters in the wrong way. Use this:
DECLARE #ParmDefinition nvarchar(500);
set #ParmDefinition = '#Id int, #ModifiedDate datetime'
set #qry = 'update '+#TableName+' set Deleted=1, ModifiedBy=#Id, ModifiedDate=#ModifiedDate where ' + #Colname + '=#Id'
execute sp_executesql #qry, #ParmDefinition, #ModifiedDate, #Id
Also pass parameter as DateTime instead of string by removing the ToString

The column ModifiedDate is a datetime field then you must pass the value as a a datetime not as a string
cmd.parameters.addwithvalue("#ModifiedDate",DateTime.Now);

Try to change your last C# row:
cmd.parameters.addwithvalue("#ModifiedDate",system.datetime.now.tostring());
with this:
cmd.Parameters.AddWithValue("#ModifiedDate",System.Datetime.Now.ToString("yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture);

Related

sql syntax error (incorrect syntax near =)

Hello I am having a problem here.
I wanted to read subjectname from a dynamic table name and the save it to a variable.
but i am getting an error
DECLARE #retval varchar(200)
DECLARE #sSQL nvarchar(500);
DECLARE #ParmDefinition nvarchar(500);
DECLARE #academicYear varchar(200) = '20212022';
Declare #subjectId varchar(200) = '202041962';
DECLARE #tablename nvarchar(50) = 'abc' + CAST(#academicyear As varchar)
DECLARE #CONDITION NVARCHAR(128)
SET #CONDITION = 'WHERE [subjectid] = 202041962'
SELECT #sSQL = N'SELECT #retvalOUT = [subjectname] FROM ' + #tablename + #CONDITION;
SET #ParmDefinition = N'#retvalOUT varchar OUTPUT';
EXEC sp_executesql #sSQL, #ParmDefinition, #retvalOUT=#retval OUTPUT;
SELECT #retval;
If you actually looked at the value of #sSQL eg by printing it, you'll note it contains FROM abc20212022WHERE, therefore,
you are not delimiting your table names - use quotename()
you need a space between your table name and the where
you should always specify a length for a varchar value (you don't need to cast a variable when concatenating two strings but you should be consistent with your use of [n]varchar)
using concat to concatenate strings is easier and safer

How to Use Dynamic Sql on Update Command?

I Had Update Command. Just Like this.
Update DispatchExceptions
SET TYPE='MWM'
WHERE ID=9801246
I want to fire same command using dynamic sql.
DECLARE #ColumnName varchar(20)=N'TYPE'
DECLARE #ColumnValue char(3)='MWM'
DECLARE #ID INTEGER = 9801246
declare #Query nvarchar(max)
SET #Query = 'Update DispatchExceptions SET '+ QUOTENAME(#ColumnName) + '''=' + #ColumnValue + '''WHERE ID =' + #ID +''
EXEC (#Query)
But it show following error.
Conversion failed when converting the nvarchar value 'Update DispatchExceptions SET [TYPE]'=MWM'WHERE ID =' to data type int.
How can I use dynamic sql in the situation. Any suggestion.
The problem here is specifically the part ' + #ID. #ID is the datatype int, which has a higher datatype precedence than nvarchar; thus any other expressions will be implicitly cast to an int (and as I'm sure you're aware, 'Update DispatchExceptions SET...' isn't an int).
If you parametrise your query, you won't have this problem:
DECLARE #ColumnName sysname = N'TYPE'; --Changed the datatype here to sysname, as the caters for all possible object names
--sysname is actually a synonym for nvarchar(128), and 128 is the maximum length for an object's name
DECLARE #ColumnValue char(3) = 'MWM';
DECLARE #ID integer = 9801246;
DECLARE #Query nvarchar(MAX);
SET #Query = N'Update DispatchExceptions SET ' + QUOTENAME(#ColumnName) + N' = #value WHERE ID = #ID;';
EXEC sp_executesql #Query,
N'#Value char(3), #ID int',
#Value = #ColumnValue,
#ID = #ID;
Also, to the OP, well done on the use of QUOTENAME. This is far too often missed out, and thus leaves your (dynamic) SQL open to injection.
The DBMS fails to add
9801246
to
Update DispatchExceptions SET [TYPE]'=MWM'WHERE ID =
because the latter is a string and canot be converted to number, which would be necessary in order to add the number 9801246 to it :-)
One solution:
DECLARE #ID varchar(7) = '9801246'
Another solution:
SET #Query = 'Update DispatchExceptions SET '+ QUOTENAME(#ColumnName) +
'''=' + #ColumnValue + '''WHERE ID =' + CAST(#ID AS VARCHAR(7)) +''
Simply cast your #ID as varchar and correct quotation before #ColumnValue as given below:
SET #Query = 'Update DispatchExceptions SET '+QUOTENAME(#ColumnName)+'='''+#ColumnValue+''' WHERE ID ='+cast(#ID as varchar)+'';

T-SQL Procedure, scalar variable error even after successful updation

--sp_executesql version
--SET #SQLQUERY = 'UPDATE #TableName SET Brief = #Brief,
-- [Full] = #Full,
-- CreatedBy = #CreatedBy,
-- Department = #Department,
-- Answer = #Answer WHERE Id=#Id';
--SET #ParamDefinition=N'#TableName nvarchar(50),#Brief nvarchar(50),#Full nvarchar(MAX),#CreatedBy varchar(256),#Department varchar(256),#Answer nvarchar(MAX),#Id int'
-- exec sp_executesql #SQLQUERY,#ParamDefinition,#TableName,#Brief,#Full,#CreatedBy,#Department,#Answer,#Id;
-- exec version
SET #SQLQUERY = 'UPDATE ' + #TableName + ' SET
Brief ='+ #Brief+',
[Full] ='+ #Full+',
CreatedBy ='+ #CreatedBy+',
Department ='+ #Department+',
Answer ='+#Answer+' WHERE Id='+CAST(#Id as nvarchar(10))
print #SQLQUERY;
EXEC (#SQLQUERY)
I have used both EXEC and sp_executesql procedures to execute my dynamic query but both are failing.
In case of EXEC the dynamic query is not set to the #SQLQUERY variable (seen after debugging), in case of sp_executesql I get scalar variable error though database is updated and I have already passed everything to it.
Case is very simple. You cannot parametrize table/column name in UPDATE statement:
SET #SQLQUERY = 'UPDATE #TableName --here is problem
SET Brief = #Brief,
[Full] = #Full,
CreatedBy = #CreatedBy,
Department = #Department,
Answer = #Answer
WHERE Id=#Id';
SET #ParamDefinition=N'#TableName nvarchar(50),#Brief nvarchar(50),
#Full nvarchar(MAX), #CreatedBy varchar(256),
#Department varchar(256),#Answer nvarchar(MAX),#Id int'
EXEC dbo.sp_executesql #SQLQUERY,#ParamDefinition,
#TableName,#Brief,#Full,
#CreatedBy,#Department,#Answer,#Id;
Use substitution instead:
SET #SQLQUERY = N'UPDATE <tab_name>
SET Brief = #Brief,
[Full] = #Full,
CreatedBy = #CreatedBy,
Department = #Department,
Answer = #Answer
WHERE Id = #Id';
SET #SQLQUERY = REPLACE(#SQLQUERY, '<tab_name>', QUOTENAME(#TableName));
SET #ParamDefinition=N'#Brief nvarchar(50),#Full nvarchar(MAX),
#CreatedBy varchar(256),#Department varchar(256),
#Answer nvarchar(MAX),#Id int';
EXEC [dbo].[sp_executesql] #SQLQUERY,
#ParamDefinition,
#Brief,#Full,#CreatedBy, #Department,#Answer,#Id;
Notes:
Table name should have SYSNAME datatype.
It is a good practice to quote identifiers with QUOTENAME (to avoid potential SQL Injection attacks).
I guess #CreatedBy is datetime that is why I do not understand why it is passed as varchar(256).
It is a good practice to end every statement with ;. In future versions this will be mandatory.

Dynamic SQL Server stored procedure with table name as input param

I have the following stored procedure
CREATE PROCEDURE [dbo].[Insert]
#Service varchar(max),
#TableName varchar(100),
#Query varchar(250),
#Results varchar(max),
#CreatedDate datetime,
#ExpirationDate datetime
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION
DECLARE #SQL NVARCHAR(MAX), #ParmDefinition NVARCHAR(MAX)
DECLARE #q1 VARCHAR(MAX), #rez1 VARCHAR(MAX),
#date1 DATETIME, #date2 DATETIME
DECLARE #tablename VARCHAR(MAX) = #Service + '.' + #TableName
SET #SQL = N'if not EXISTS (select #q from ' + #tablename + ' where Query = #q) insert into ' + #tablename + ' values(#q, #rez, #date1, #date2)'
SET #ParmDefinition = N'#q varchar(max), #rez varchar(max),
#date1 datetime, #date2 datetime'
EXECUTE sp_executeSQL -- Dynamic T-SQL
#SQL,
#ParmDefinition,
#q = #Query,
#rez = #Results,
#date1= #CreatedDate,
#date2 = #ExpirationDate
COMMIT TRANSACTION
END
When I try to execute it, it doesn't insert anything, 0 rows
If I execute the code without the stored procedure, like a single query it inserts
Am I missing something?
There are a lot of things you have done in your question which doesnt make any sense to me, Why do you need to declare all these variables inside your procedure.
Yes true you are using parametrised query to protect yourself against sql injection attack, yet you left a hole by concatenating the object names (Table and database name), yes you will need to concatenate them but you can use QUOTENAME() function around them passed parameters and enforce sql server to put square brackets around these parameters and force sql server to treat them as nothing else but object names.
And Selecting a variable in IF EXISTS not make much sense. Select 1 which returns true if a row is found with matching criteria , and if no row is found it will simply insert a row.
Only declare variables that needs to declared, otherwise this make it look like a mess and difficult to debug. As they say Keep it simple :)
Also use appropriate data types for your parameters, #Service I believe is your database name why does it need to be a VARCHAR(MAX) data type, use the data type specific to store Sql Server Object names SYSNAME.
CREATE PROCEDURE [dbo].[Insert]
#Service SYSNAME,
#TableName SYSNAME,
#Query varchar(250),
#Results varchar(max),
#CreatedDate datetime,
#ExpirationDate datetime
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION
DECLARE #SQL NVARCHAR(MAX), #ParmDefinition NVARCHAR(MAX)
SET #SQL = N'IF NOT EXISTS (select 1 from ' + QUOTENAME(#Service) + '.' + QUOTENAME(#TableName)
+ N' where Query = #q) '
+ N'insert into ' + QUOTENAME(#Service) + '.' + QUOTENAME(#TableName)
+ N' values(#q, #rez, #date1, #date2)'
SET #ParmDefinition = N'#q varchar(250), #rez varchar(max),
#date1 datetime, #date2 datetime'
EXECUTE sp_executeSQL #SQL
,#ParmDefinition
,#q = #Query
,#rez = #Results
,#date1= #CreatedDate
,#date2 = #ExpirationDate
COMMIT TRANSACTION
END

SP_ExecuteSQL with Parameters doesn't like Contains clause

I've been tasked with modifying a stored procedure so that it goes from looking like this:
DECLARE #ID nvarchar(10)
SET #ID = '0000000001'
DECLARE #SQL nvarchar(200)
SET #SQL = 'SELECT AppN FROM Apps WHERE CONTAINS(ID, ''"*'' + #ID + ''*"'')'
EXECUTE SP_EXECUTESQL #SQL
to using the parameter list for SP_EXECUTESQL and not string concatenation. The issue is that the following doesn't appear to work:
DECLARE #CID nvarchar(10)
SET #CID = '0000000001'
DECLARE #ID2 nvarchar(14)
SET #ID2 = '"*' + #ID + '*"'
DECLARE #SQL nvarchar(200)
SET #SQL = 'SELECT AppN FROM Apps WHERE CONTAINS(ID, ID2)'
DECLARE #ParamDefinition NCHAR(300)
SET #ParamDefinition = '#ID2 nvarchar(10)'
EXECUTE SP_EXECUTESQL #SQL, #ParamDefinition, #ID2
For whatever reason, the first set of statements works fine. The second does not. I get the following error message: Syntax error near '"' in the full-text search condition '"*00000000'.
If I remove 4 characters from #ID the second set of statements also works. Clearly it has something to do with the length of either #ID or the column ID but I can't figure out what.
You define #ID2 as nvarchar(10) in your parameters for the dynamic SQL.
It's actually 14 characters, so you are cutting off the end of it.
This outputs the correct variable for me:
DECLARE #CID nvarchar(10)
SET #CID = '0000000001'
DECLARE #ID2 nvarchar(14)
SET #ID2 = '"*' + #CID + '*"'
DECLARE #SQL nvarchar(200)
SET #SQL = 'SELECT #ID2'
DECLARE #ParamDefinition NCHAR(300)
SET #ParamDefinition = '#ID2 nvarchar(14)'
EXECUTE SP_EXECUTESQL #SQL, #ParamDefinition, #ID2