Problem passing a datetime variable into a dynamic SQL query - sql-server

I'm trying to execute a dynamic SQL query, but I'm getting an error Msg 105, Level 15, State 1, Line 1
Unclosed quotation mark after the character string '2020-09-15 18:'.
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '2020-09-15 18:'
There must be something wrong with the datetime variable.
Can anybody suggest how this should be done properly ?
declare #paramDailyOutput nvarchar(100), #retrieveDailyVal real
declare #paramDaily float
declare #retrieveDailyID varchar(100) = 'table_53'
declare #startTime datetime, #currTime datetime = GETDATE()
set #startTime = DATEADD(hour, -1, #currTime)
set #paramDailyOutput = 'SELECT #paramDaily = max(value) - min(value) FROM ' + #retrieveDailyID + ' where read_date between ''' + convert(nvarchar(200), #startTime, 120) + ''' and ''' + convert(nvarchar(200), #currTime, 120) + ''''
exec sp_executesql #paramDailyOutput, N' #paramDaily float OUTPUT', #paramDaily = #paramDaily output
select #paramDaily

You strings are too short, you're going way over 100 characters.
Try changing everything to 250 or even 300 characters. Or better yet, NVARCHAR(1000).

Related

Dynamic OPENQUERY with DATETIME criteria

Can someone please explain to me what is wrong with the below expression. I believe that's I'm converting my date correctly using CONVERT 126 and that my quotes are escaped correctly using char 39 but I could be wrong.
T-SQL:
DECLARE #end2 DATETIME2 = GETDATE();
DECLARE #test2 nvarchar(200) = N'SELECT * FROM OPENQUERY(x, '
+ char(39) + 'SELECT OBJID FROM SALE WHERE MODIFIED >= '
+ CHAR(39) + CONVERT(nvarchar(24),#end2,126)
+ char(39) + char(39) + ')';
PRINT #test2;
EXEC (#test2);
Print output:
select * from openquery(x, 'SELECT OBJID FROM SALE
WHERE MODIFIED >= '2023-01-19T11:55:21.1233'')
Error:
Msg 102, Level 15, State 1
Incorrect syntax near '2023'.
Tried different formats, casting, etc. I can't use EXEC x..sys.sp_executesql because x is Firebird, not another SQL Server.
You can escape the ' character with another one, i.e. ''. But you need to double escape it, i.e. your final string needs to have double single quotes in to be escaped in your dynamic SQL, which means a lot of escaping, i.e.
DECLARE #end2 DATETIME2
set #end2 = getdate()
declare #test2 nvarchar(200)
set #test2 = 'select * from openquery(x, ''SELECT OBJID FROM SALE WHERE MODIFIED >= '''''+convert(nvarchar(24),#end2,126)+''''''')'
print #test2
exec (#test2)
Which results in:
select *
from openquery(x, 'SELECT OBJID FROM SALE WHERE MODIFIED >= ''2023-01-19T18:06:22.6033''')

What am I missing to execute stored procedure in OpenQuery

I am trying to use OpenQuery to insert data into a temporary table. OpenQuery suppose to execute a stored procedure that outputs hundreds of rows.
In order to not to defining Create Table #temp1, I am trying to execute OpenQuery and inserting the result into #temp1 table using into statement in Select query. I would like to know what is causing it not to execute?
It seems like it may quotes issue which is not placed correctly. How can I get help related to this?
My server contains multiple databases (instances). How do I need to define it here?
I am providing an example here of my query here
DECLARE #startDate DATETIME = CONVERT(DATE, GETDATE());
DECLARE #endDate DATETIME = CONVERT(DATE, GETDATE()+1);
DECLARE #stDate NVARCHAR(MAX) = CHAR(39) + CONVERT(NVARCHAR(255), #startDate, 23)+ CHAR(39) + ',';
DECLARE #enDate NVARCHAR(MAX) = CHAR(39) + CONVERT(NVARCHAR(255), #endDate, 23) + CHAR(39);
DECLARE #execCommand NVARCHAR(MAX) = CHAR(39) + 'EXEC dbo.getRecordsByOrderDate ' ;
DECLARE #concatCommand NVARCHAR(MAX) = #execCommand + #stDate + #enDate + CHAR(39);
DECLARE #opQuery Nvarchar(MAX) = 'Select * Into #Temp1 from Openquery(LOCALSERVER, '+ #concateCommand +') oq'
EXEC (#opQuery);
Error Message:
Msg 102, Level 15, State 1, Line 20 Incorrect syntax near '2020'.
If I try to execute in below format
Select * Into #Temp1 from Openquery(LOCALSERVER, 'EXEC dbo.getRecordsByOrderDate ''2020-12-11'',''''2020-12-12''''') oq
Msg 11529, Level 16, State 1, Procedure
sys.sp_describe_first_result_set, Line 1 [Batch Start Line 31] The
metadata could not be determined because every code path results in an
error; see previous errors for some of these.
Msg 2812, Level 16,
State 62, Procedure sys.sp_describe_first_result_set, Line 1 [Batch
Start Line 31] Could not find stored procedure
'dbo.getRecordsByOrderDate'.
The problem is your lack of escapting the quotes on your injected parameters. The simplest way to debug dynamic code is to PRINT/SELECT it. If you do that you'll quickly see the problem:
DECLARE #startDate DATETIME = CONVERT(DATE, GETDATE());
DECLARE #endDate DATETIME = CONVERT(DATE, GETDATE()+1);
DECLARE #stDate NVARCHAR(MAX) = CHAR(39) + CONVERT(NVARCHAR(255), #startDate, 23)+ CHAR(39) + ',';
DECLARE #enDate NVARCHAR(MAX) = CHAR(39) + CONVERT(NVARCHAR(255), #endDate, 23) + CHAR(39);
DECLARE #execCommand NVARCHAR(MAX) = CHAR(39) + 'EXEC dbo.getRecordsByOrderDate ' ;
DECLARE #concatCommand NVARCHAR(MAX) = #execCommand + #stDate + #enDate + CHAR(39);
DECLARE #opQuery Nvarchar(MAX) = 'Select * Into #Temp1 from Openquery(LOCALSERVER, '+ #concatCommand +') oq'
PRINT #opQuery;
Which returns...
Select *
Into #Temp1
from Openquery(LOCALSERVER, 'EXEC dbo.getRecordsByOrderDate '2020-12-11','2020-12-12'') oq
Voila your first parameter escapes the second parameter, and thus the error. (I Have added additional lines, as SO's choice of "prettifier" thinks # is a comment character in SQL, and I want the escaping to be highlighted in the colouring.)
When using single quotes inside a literal string, you need to escape them by "doubly them up" (''). Thus the final statement needs to me the below:
Select *
Into #Temp1
from Openquery(LOCALSERVER, 'EXEC dbo.getRecordsByOrderDate ''20201211'',''20201212''') oq
(Additional lines added for presentation again.)
So you need to fix the definitions of your 2 injected values:
DECLARE #stDate NVARCHAR(8) = CHAR(39) + CHAR(39) + CONVERT(NVARCHAR(8), #startDate, 112)+ CHAR(39) + CHAR(39) + ',';
DECLARE #enDate NVARCHAR(8) = CHAR(39) + CHAR(39) + CONVERT(NVARCHAR(8), #endDate, 112) + CHAR(39) + CHAR(39);
Note I change the data types and styles too. The style as yyyy-MM-dd isn't unambiguous in SQL Server, and the data types, as you don't need 2 billion characters for a date.
Note, however, that after executing this you still won't be able to access #Temp1. A temporary table only persists for the scope it was created in, and that scope is the dynamic SQL's. You'll need to use a permanent table inside the dynamic statement, or CREATE a temporary table outside of the dynamic statement to use it outside of it.

Set a Value in Verbal using sql

I want to set "InOperator" value in a Verbal. This is my select Query.
DECLARE #i nvarchar(Max); set #i = '619, 618, 620, 2162, 2173, 3613, 2090';
select * from tbl_PharmacypurDetail where ItmCode in (CAST(#i as bigint))
Result
Msg 8114, Level 16, State 5, Line 2
Error converting data type nvarchar to bigint.
You can use STRING_SPLIT to splits a string into rows of substrings, based on a specified separator character.
DECLARE #i nvarchar(Max); set #i = '619, 618, 620, 2162, 2173, 3613, 2090';
select * from tbl_PharmacypurDetail where ItmCode in (SELECT value FROM STRING_SPLIT(#i, ','))
You can use split function :
select tp.*
from tbl_PharmacypurDetail tp cross apply
dbo.splitfn(#i, ',') as t(val)
where t.val = tp.itemcode;
If you are working with SQL Server 2016 or higher then you can use STRING_SPLIT.
You can use something like this instead in case your server doesn't support STRING_SPLIT:
DECLARE #i nvarchar(Max);
SET #i = '619, 618, 620, 2162, 2173, 3613, 2090';
SELECT *
FROM tbl_PharmacypurDetail
WHERE CHARINDEX(',' + CONVERT(NVARCHAR(MAX), ItmCode) + ',', ',' + REPLACE(#i, ' ', '') + ',') > 0

SQL Parameterised column names

I am trying to create a parameterised query for retrieving data back from a table
Essentially I have a table structure of
ID
nvarchar1
ntext
datetime1
datetime2
and I am trying to do a query like so that it selects all the data where the current date is greater than datetime1 and less than datetime2
SELECT
ID, nvarchar1,
ntext,
datetime1,
datetime2
FROM
TABLEName
WHERE
datetime1 >= #CurrentDate
AND datetime2 <= #CurrentDate
I want to make the columns parameters such as
#TableName, #CurrentDate, #StartDate, #EndDate
DECLARE #TableName NVARCHAR(100);
SET #TableName = '[Surveys].[dbo].[Table]'
DECLARE #CurrentDate DateTime;
SET #CurrentDate = GETDATE();
DECLARE #StartDate NVARCHAR(100);
SET #StartDate = 'datetime1'
DECLARE #EndDate NVARCHAR(100);
SET #EndDate = 'datetime2'
DECLARE #sql nvarchar(1000)
SET #sql = 'SELECT * FROM ' + #TableName + 'WHERE' + #EndDate + '>=' + #CurrentDate + 'AND' + #StartDatedatetime1 + '<=' + #CurrentDate
EXEC(#sql)
The data is going to be coming from a SP data source so I have no control of the column names etc. and when I create the SP Lists they automatically assign to a table column of that type so this is why I need to columns to be parameters.
Using the above code which I thought should work returns
Msg 241, Level 16, State 1, Line 14
Conversion failed when converting date and/or time from character string.
What am I doing wrong?
Try the below. As #GordonLinoff stated, you where missing the single quotes (') from around the #CurrentDate variable. Also, you where passing a DATETIME parameter in to the #sql variable which is an NVARCHAR data type. These are not implicitly converted, so the #CurrentDate variable needs to be converted to a NVARCHAR first:
DECLARE #sql nvarchar(1000)
SET #sql = 'SELECT * FROM ' + #TableName
+ ' WHERE ' + #EndDate + ' >= ''' + CONVERT(NVARCHAR(50), #CurrentDate,120)
+ ''' AND ' + #StartDate + ' <= ''' + CONVERT(NVARCHAR(50), #CurrentDate,120) + ''''
EXEC(#sql)
You are pretty close. I would construct the SQL for the table and then use parameters for the current date: This would be something like this:
SET #sql = '
SELECT *
FROM #TableName
WHERE datetime2 >= #CurrentDate AND datetime1 <= #CurrentDate';
SET #sql = REPLACE(#sql, '#TableName', #TableName);
exec sp_executesql #sql, N'#CurrentDate date', #CurrentDate = #CurrentDate;
Incidentally, the problem with your query is the lack of single quotes around the date constants.
EDIT:
You cannot substitute column or table names using parameters. I would write the code as:
SET #sql = '
SELECT *
FROM #TableName
WHERE #datetime2 >= #CurrentDate AND #datetime1 <= #CurrentDate';
SET #sql = REPLACE(#sql, '#TableName', #TableName);
SET #sql = REPLACE(#sql, '#datetime1', #DateTime1);
SET #sql = REPLACE(#sql, '#datetime2', '#DateTime2);
. . .
I use REPLACE() for this type of operation because the code is easier to understand and to maintain.

How to convert/cast column data type in concatenated SQL query string

i have the following variables defined in my stored procedure
#StartDate DateTime,
#EndDate DateTime,
I'm setting the sql to be executed dynamically, so when constructing the query where clause i have the below line.
SET #sql = #sql + ' AND (convert(datetime, R.ReportDate, 121) >= ' + #StartDate + 'AND convert(datetime, R.ReportDate, 121) <=' + #EndDate +')'
When i execute the stored procedure, the line above throws the error below
Conversion failed when converting datetime from character string.
If i change the variable datatype to NVARCHAR(MAX), the procedure executes successfully but then returns no rows because the date comparison/matching fails.
ReportDate column is of datatype datetime and has data in this format 2014-06-01 00:00:00.000
As you can see i have tried converting the column when constructing my query but that isn't working.
The problem is not with ReportDate, but when you are trying to concatenate your DateTime parameters with your nvarchar sql statement. The problem can be reproduced fairly simply with:
DECLARE #SQL NVARCHAR(MAX) = 'Some text' + GETDATE();
The wrong way to fix this is to convert the datetime parameter to a string so that it can be concatenated with a string, e.g.
SET #sql = #sql + ' AND r.ReportDate >= CONVERT(DATETIME, '''
+ CONVERT(VARCHAR(10), #StartDate, 112)
+ ''', 112) AND r.ReportDate <= CONVERT(DATETIME, ''' +
+ CONVERT(VARCHAR(10), #EndDate, 112)
+ ''', 112)';
N.B. I am including this for completeness of the answer, and in no way endorse this approach
The correct way to fix this is to use sp_executesql and pass properly typed parameters this way, this will avoid conversion issues. e.g.
SET #sql = #sql + 'AND r.ReportDate >= #StartDateParam AND r.ReportDate <= #EndDateParam';
EXECUTE sp_executesql
#sql,
N'#StartDateParam DATETIME, #EndDateParam DATETIME',
#StartDateParam = #StartDate,
#EndDateParam = #EndDate

Resources