Dynamic Sp_Executesql failing on datetime conversion error - sql

I have a very simple dynamic SQL query that specifically needs to be called using sp_executesql with parameters. This query works fine in regular dynamic SQL, but fails when using sp_executesql on a conversion error.
I have tried many combinations of dynamic SQL, but none of them seem to work specifically for datetime conversions related to sp_executesql.
declare
#sql_nvarchar nvarchar(max),
#datetime datetime = GETDATE(),
#sqlparams nvarchar(max),
#tablename nvarchar(max) = 'SomeTableName'
Set #sql_nvarchar =
N'
Select *
from ' + #tablename + '
where Date > ''' + convert(nvarchar(23), #datetime, 101) + ''' '
Set #sqlparams =
N'
#datetime datetime,
#tablename nvarchar(max)
'
EXEC(#sql_nvarchar)
EXEC [sp_executesql] #sql_nvarchar,#sqlparams, #datetime, #tablename
The first exec correctly returns the desired query, the second EXEC throws an error: 'Error converting data type nvarchar(max) to datetime.'

You cannot parameterize an identifier, such as a table name. So, phrase this as:
Set #sql_nvarchar = N'
Select *
from ' + #tablename + '
where Date > #datetime
';
Set #sqlparams = N'#datetime datetime'
exec sp_executesql #sql_nvarchar, #sqlparams,
#datetime=#datetime

Related

Dynamic SQL stored procedure and datetime

I have a simple query that I want to convert to dynamic SQL. I have 2 input parameters: a table and a datetime. And the output is the rowcount for the table and this specific datetime.
CREATE PROCEDURE [etl].[ROWCOUNT_TST2]
(#P_LOAD_TARGET nvarchar(250),
#P_LOAD_DATE DATETIME)
AS
BEGIN
DECLARE #SQL nvarchar(1000)
SET #SQL = 'SELECT COUNT(*) as Inserted FROM'+#P_LOAD_TARGET +' WHERE VALID_FROM ='''+ #P_LOAD_DATE+''' AND VALID_TO IS NULL'
EXEC (#SQL)
END;
GO
I tried different solutions. I tried the query with execute sp_executesql, I tied to add the the ''' before and after the #P_LOAD_DATE. I am probably missing something here.
When I execute the stored procedure with a table name and datetime like 2021-05-06 06:41:52.557, I get the following error:
Conversion failed when converting date and/or time from character string.
But why?
I even tried to add a conversion to datetime like this, but I still get the same error.
SET #SQL = 'SELECT COUNT(*) as Inserted FROM'+#P_LOAD_TARGET +' WHERE VALID_FROM = convert(datetime,'''+ #P_LOAD_DATE+''') AND VALID_TO IS NULL'
But when I execute SELECT convert(datetime, '2021-05-06 06:41:52.557') it works out fine. I am just confused right now and can't find the root of the problem.
Edit: valid_from is a datetime in the target table. So that is also not the reason for the problem
You need to properly and safely inject your dynamic object name and parametrise your parameter:
CREATE PROCEDURE [etl].[ROWCOUNT_TST2](#P_LOAD_SCHEMA sysname = N'dbo', --Always define your schema
#P_LOAD_TARGET sysname, --sysname is the data type for objects, a synonym of nvarchar(128) NOT NULL
#P_LOAD_DATE datetime) AS
BEGIN
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET #SQL = N'SELECT COUNT(*) AS Inserted' + #CRLF +
N'FROM ' + QUOTENAME(#P_LOAD_SCHEMA) + N'.' + QUOTENAME(#P_LOAD_TARGET) + #CRLF +
N'WHERE VALID_FROM = #P_LOAD_DATE' + #CRLF +
N' AND VALID_TO IS NULL;';
--PRINT #SQL; --Your best friend.
EXEC sys.sp_executesql #SQL, N'#P_LOAD_DATE datetime', #P_LOAD_DATE;
END;

Invalid column name error when using QUOTENAME

I have several tables having the same structure. The tables are named by year that is 2001,2002 and so on. I am in need to search a column for a value in each table and get the count for each table.
I have created a stored procedure below but I keep getting an error
Invalid column 'lol'
This is the stored procedure used:
CREATE PROCEDURE [dbo].[CountSP]
#TableName NVARCHAR(128),
#SearchParam NVARCHAR(50),
#SearchInput NVARCHAR(200)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'SELECT COUNT('+QUOTENAME(#SearchParam)+') FROM ' + QUOTENAME(#TableName) +'WHERE'+QUOTENAME(#SearchParam)+'LIKE '+QUOTENAME(#SearchInput)+
+ N' SELECT * FROM '+QUOTENAME(#TableName)
EXECUTE sp_executesql #Sql
END
Executing it:
DECLARE #return_value INT
EXEC #return_value = [dbo].[CountSP]
#TableName = N'1999',
#SearchParam = N'USERDESC',
#SearchInput = N'lol'
SELECT 'Return Value' = #return_value
I don't know why you are using LIKE operator there while you don't use wildcards, also use SysName datatype directly for object names.
Create PROCEDURE [dbo].[CountSP]
(
#TableName SysName,
#SearchInput NVARCHAR(50),
#SearchParam SysName
)
AS
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX) = N'SELECT COUNT(' +
QUOTENAME(#SearchParam) +
N') FROM ' +
QUOTENAME(#TableName) +
N' WHERE ' +
QUOTENAME(#SearchParam) +
N' = ' + --You can change it to LIKE if needed
QUOTENAME(#SearchInput, '''') +
N';';
-- There is no benifits of using LIKE operator there
EXEC sp_executesql #SQL;
Then you can call it as
EXEC [dbo].[CountSP] N'YourTableNameHere', N'SearchInput', N'ColumnName';
This is because it is currently translated to :
SELECT COUNT([USERDESC]) FROM [1999] WHERE [USERDESC] LIKE [lol]
this means that it is comparing the "USERDESC" column with the "lol" column but from what I am understanding lol isn't a column but a value? which means you should lose the QUOTENAME for that variable.
See the documentation here : https://learn.microsoft.com/en-us/sql/t-sql/functions/quotename-transact-sql?view=sql-server-2017
You need to pass your parameter #SearchInput as a parameter to sp_execute:
CREATE PROCEDURE [dbo].[CountSP] #TableName sysname, --This is effectively the same datatype (as sysname is a synonym for nvarchar(128))
#SearchParam sysname, --Have changed this one though
#SearchInput nvarchar(200)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql nvarchar(MAX);
SET #Sql = N'SELECT COUNT(' + QUOTENAME(#SearchParam) + N') FROM ' + QUOTENAME(#TableName) + N'WHERE' + QUOTENAME(#SearchParam) + N' LIKE #SearchInput;' + NCHAR(13) + NCHAR(10) +
N'SELECT * FROM ' + QUOTENAME(#TableName);
EXECUTE sp_executesql #SQL, N'#SearchInput nvarchar(200)', #SearchInput;
END;
QUOTENAME, by default, will quote a value in brackets ([]). It does accept a second parameter which can be used to define a different character (for example QUOTENAME(#Value,'()') will wrap the value in parentheses). For what you want though, you want to parametrise the value, not inject (a quoted) value.

Concatenate Date in sql Dynamic query

I am trying to execute a dynamic query in which I am concatenating a date but failed in doing
DECLARE #pStartDate datetime
DECLARE #pEndDate datetime
DECLARE #query nvarchar(MAX)
Dynamic query1
set #query = 'Select * from Table1 From tblEvent
Where (EventDate Between' + #pStartDate + ' and ' + #pEndDate +')'
Exec(#query)
Error
Conversion failed when converting date and/or time from character string.
Dynamic query2
set #query = 'Select * from Table1 From tblEvent
Where (EventDate Between' + cast(#pStartDate as varchar) + ' and ' + cast(#pEndDate as varchar) +')'
Exec(#query)
Error
Incorrect syntax near 1 [1 stands for whatever date I passed to #pStartDate]
Please suggest me how to do it.
Thanks.
The really proper way to do this would be to use a parametrized query and having sp_executeSql execute this:
DECLARE #pStartDate datetime
DECLARE #pEndDate datetime
DECLARE #query nvarchar(MAX)
SET #pStartDate = '20080301'
SET #pEndDate = '20080331'
-- if you're setting a NVARCHAR variable - **DO USE** the N'..' prefix!
SET #query = N'SELECT * FROM dbo.Table1
WHERE OrderDate BETWEEN #StartDate AND #EndDate'
-- execute the dynamic SQL, with a list of parameters, and their values
EXEC sp_executesql #query,
N'#StartDate DATETIME, #EndDate DATETIME',
#StartDate = #pStartDate, #EndDate = #pEndDate
In that case, there's no fiddling around with string concatenation and missing quotes and messy stuff like that - just a clear, properly parametrized query that isn't vulnerable to SQL injection attacks, and that performs much better since it's execution plan can be reused for subsequent executions.
Add single quote.
Because date or string specify in single quote like this '12-01-2014'.
set #query = 'Select * from Table1 From tblEvent
Where (EventDate Between''' + #pStartDate + ''' and ''' + #pEndDate +''')'

Report Builder paramter dropdown to choose column name

I have a parameter with the available values as column names and a I am using that parameter in the sql query
WHERE ((#ColumnName) BETWEEN (#StartDate) AND (#EndDate))
AND (schema.table.column_name LIKE (#Number))
When i try to run the report i get a cannot convert date/time from characters
If i remove the #ColumnName parameter the report runs fine but i want the ability to choose a column to search the date against.
If you want pass Column name dynamically you will need to use a stored procedure to do this using dynamic sql something like this....
CREATE PROCEDURE Get_Data
#ColumnName1 SYSNAME,
#ColumnName2 SYSNAME,
#StartDate DATETIME,
#EndDate DATETIME,
#Number VARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = N'SELECT * FROM TableName'
+ N'WHERE ' + QUOTENAME(#ColumnName1) + N' BETWEEN #StartDate AND #EndDate '
+ N' AND ' + QUOTENAME(#ColumnName2) + N' LIKE ''#Number'' '
EXECUTE sp_executesql #SQL
,N'#StartDate DATETIME, #EndDate DATETIME, #Number VARCHAR(100)'
,#StartDate
,#EndDate
,#Number
END

SQL Linked Server query with Parameters

I need to select value from SQL Linked Server & get it to loacal variable
This is what I've written so far:
DECLARE #SQLQUERY AS VARCHAR(1000)
DECLARE #FINALQUERY AS VARCHAR(1000)
DECLARE #OutVal AS VARCHAR(10)
SET #SQLQUERY = 'SELECT Field1 FROM Table1 WHERE Field2=' + CAST(#var1 AS VARCHAR)
SET #FINALQUERY = 'SELECT #OutVal=Field1 FROM OPENQUERY(LINKEDSERVER,' + '''' + #SQLQUERY + '''' + ')'
EXEC(#finalQuery)
but this is wrong as it does not set the local variable(#OutVal).
Instead of exec, use sp_execute_sql with an output parameter:
exec sp_executesql #FinalQuery, N'#OutVal output', #OutVal = #OutVal out
Since sp_executesql expects nvarchar parameters, be sure to change the definition of #FinalQuery to nvarchar(max).
#OutVal in query string does not recognized as a variable. use a function or return table statement.