12

I am using a dynamic query wherein I want to use the variable which holds the datetime, whenever I execute the query it says cannot convert datetime from string, when I cast that variable to varchar(max), it takes it as string and not datetime, so how should I execute the query..

Below is my SQL query which I am trying to execute.

SET @SQL1 = 'SELECT B.FacId, B.FacName, B.BookCode, B.BookName, B.Quantity, 
CONVERT(VARCHAR(10), B.TillDate, 104) AS TILLDATE FROM '+@TABLE+' B
WHERE B.TillDate BETWEEN CONVERT(VARCHAR(10),'+@FROMDATE+', 101) and 
CONVERT(VARCHAR(10), DATEADD(DD,1,'+@TODATE+'), 101)'

EXEC SP_EXECUTESQL @SQL1

here @fromdate and @todate are the datetime type coming from different temp table. and stored in these variable..

How should I execute this query?

8 Answers 8

38

You need to quote your dates..

SET @SQL1 = 
   'SELECT B.FacId, 
           B.FacName, 
           B.BookCode, 
           B.BookName, 
           B.Quantity, 
           CONVERT(VARCHAR(10), B.TillDate, 104) AS TILLDATE 
           FROM '+@TABLE+' B 
           WHERE B.TillDate BETWEEN ''' + CONVERT(VARCHAR(10),@FROMDATE, 101) + ''' and ''' + CONVERT(VARCHAR(10),DATEADD(DD,1,@TODATE), 101) + ''''
Sign up to request clarification or add additional context in comments.

1 Comment

This is the right answer. I had the exact same issue and this solved it.
9

You should not concatenate your parameter values like this. The best solution is to use a parameterized query with sp_executesql.

DECLARE @sql nvarchar(4000)

select @sql = N'
  SELECT B.FacId 
       , B.FacName
       , B.BookCode
       , B.BookName
       , B.Quantity
       , CONVERT(VARCHAR(10), B.TillDate, 104) AS TILLDATE 
    FROM ' + quotename(@TABLE) + N' B
   WHERE B.TillDate BETWEEN cast(floor(cast(@fromDate as float)) as datetime)
                        AND cast(floor(cast(@toDate as float)) as datetime)'

EXEC sp_executesql @sql, N'@fromDate datetime, @toDate datetime', @FROMDATE, @TODATE

Things to note about sp_executesql are:

  • The parameters are NVARCHAR values
  • The 3rd and 4th parameter keep their original datatype and do not need to be converted to a varchar. This again protects agains SQL Injection and it makes the query more readable as you prevent the quote soup which is so common in Dynamic SQL

Some additional changes were applied to the query:

  • The table name is wrapped in the QUOTENAME() function which protects against sql injection on the object name
  • The way the date part of the datetime variables is removed is not very optimal. Doing a convert(,,101) is an expensive operation which can better be done using the casting to float and taking floor of that value.

4 Comments

What's the point in taking @fromDate which is a datetime then casting it to a float just to cast it back to a datetime again?
@joel This chops off the timestamp part of the datetime without converting to a string. (Dates are numeric internally)
Would you please specify on why is it the best approach. Is it because 'cast(float(cast' tastes better that some soup + CONVERT(VARCHAR(10),@FROMDATE, 101) or anything else?
I haven't checked performance of the convert versus cast to float in the last 10 years, but it used to be slower.
2

I'd like to see your variable definitions but I suspect it's because @FROMDATE and @TODATE are datetime and you're using them in a string concatenation statement. Thus you can fix it by:

SET @SQL1 = 'SELECT B.FacId, B.FacName, B.BookCode, B.BookName, B.Quantity, CONVERT(VARCHAR(10), B.TillDate, 104) AS TILLDATE FROM '+@TABLE+' B WHERE B.TillDate BETWEEN CONVERT(VARCHAR(10),'+CAST(@FROMDATE as varchar(15))+', 101) and CONVERT(VARCHAR(10), DATEADD(DD,1,'+CAST(@TODATE as varchar(15))+'), 101)'

However better solutions are:

  1. Don't use dynamic SQL at all, maybe @TABLE doesn't vary that much and you can union them in to a view or something
  2. Pass the parameters directly in to sp_executeSQL and thus preserve their types e.g.

SET @SQL1 = 'SELECT B.FacId, B.FacName, B.BookCode, B.BookName, B.Quantity, B.TillDate AS TILLDATE FROM '+@TABLE+' B WHERE B.TillDate BETWEEN @inFROMDATE and @inTODATE'

EXEC SP_EXECUTESQL @SQL1,'@inFROMDATE datetime, @inTODATE',@inFromDate = @FROMDATE, @inTODATE = @TODate

Comments

2

I think this might work:

 DECLARE @tempdate datetime
 SET tempdate =DATEADD(DD,1,@TODATE)
 SET @SQL1 = 'SELECT B.FacId, B.FacName, B.BookCode, B.BookName, B.Quantity,'''+  cast     (B.TillDate as VARCHAR(50))+''' AS TILLDATE FROM '+@TABLE+' B WHERE B.TillDate BETWEEN '''+cast(@FROMDATE as VARCHAR(50))+''' and  '''+cast(@tempdate as VARCHAR(50))'''

 EXEC SP_EXECUTESQL @SQL1 

Comments

0

Try this:

declare @sql1 varchar(max)
declare @table sysname
declare @FROMDATE datetime
declare @TODATE datetime

set @table = 'MyTable'
set @FROMDATE = GETDATE()
set @ToDATE = GETDATE()


SET @SQL1 = 'SELECT B.FacId, B.FacName, B.BookCode, B.BookName, B.Quantity, 
CONVERT(VARCHAR(10), B.TillDate, 104) AS TILLDATE FROM '+@TABLE+' B
WHERE B.TillDate BETWEEN CONVERT(Datetime,''' + CONVERT(VARCHAR(10),@FROMDATE, 101) 
+ ''', 101) and CONVERT(DATETIME,'''+ CONVERT(VARCHAR(10), DATEADD(DD,1,@TODATE), 101) + ''', 101)'


print @sql1

But look at Joel Mansford's answer to avoid the double conversion.

Comments

0

This is late, but may be it help someone

What you need is a quotes around your date, You already got your answer.

Below is an example of what I usually put in my query

'(CONVERT(DATETIME,CONVERT(varchar,gd.CreatedDate),106) <= CONVERT(DATETIME,'''+CONVERT(varchar, @EndDate ) +''',106))'

note that @EndDate is of type Datetime here

Comments

0

Run this example and adapt it to your code. (There are not 3 contiguous single quotes)

Declare @FromDATE  datetime
;Declare @ToDATE datetime
;set @FromDATE = getdate() 
;set @ToDATE = @FromDATE 

;Print 'WHERE TillDate BETWEEN ' + char(39) + CONVERT(VARCHAR(10),@FromDATE, 101) 
+ char(39) + ' and ' + char(39) + CONVERT(VARCHAR(10),@ToDATE, 101) + char(39)

1 Comment

instead of doing this you can add something like ''some text''
0

I needed to pass a date as a variable to a stored procedure I was executing within the dynamic SQL:

Declare @asOfDate date = '2020-01-01'
Declare @sql nvarchar(max)

Set @sql='SELECT * FROM OPENROWSET(''SQLNCLI''
        ,''Server=localhost;Database=YOURDB;Uid=DBO_DB;Pwd=password''
        ,''SET FMTONLY OFF;SET NOCOUNT ON;
                declare @date date ;
                select @date = CONVERT(DATE,CONVERT(varchar(10),'+ CONVERT(VARCHAR(100),@asOfDate , 112)+'));

                exec your_proc_here @date

                '')'

 Print @sql
 --Exec(@sql)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.