Passing variables in OPENQUERY - concatenation

I have no doubt I'm missing something minute, but nonetheless, I'm not sure what it is. Here's the query:
DECLARE #START DATE, #END DATE, #MySQL VARCHAR(MAX)
SELECT #START = '12/1/2020'
SELECT #END = '12/10/2020'
SET #MySQL =
'SELECT * FROM OPENQUERY ([SERVERNAME], ''SELECT * FROM TABLE (NOLOCK) WHERE InitiatedDate BETWEEN ' + #Start + ' AND ' + #End + ')'
EXEC (#MySQL)
I get this error:
The data types varchar and date are incompatible in the add operator
I tested this concatenation method with a similar query and it worked, no problem:
SET #MySQL =
'SELECT * FROM OPENQUERY ([SERVER], ''SELECT top ' + #X + ' * FROM TABLE'')'
EXEC (#MySQL)

Your second example is probably working because #X was a VARCHAR data type.
In your main example, #START and #END are defined as DATE data types, so logically you cannot append them to a VARCHAR data type in the same way that adding 6 and 'six' doesn't result in either of 12 or '6six'.
You need to make use of the CONVERT function to change your DATE back to the string representation of a DATE. Be careful to use the format option to get the string in a format that can then be automatically converted back to a DATE when the query runs.
'SELECT * FROM OPENQUERY ([SERVERNAME], ''SELECT * FROM TABLE (NOLOCK) WHERE InitiatedDate BETWEEN ''' + CONVERT(varchar(10), #Start, 101) + ''' AND ''' + CONVERT(varchar(10), #End, 101) + ''')'

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.

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

SQL Server EXEC backup table with date dynamically

I am looking to backup a table and auto add the date to the end of the table name.
Here is what I have
declare #table char(36)= 'template_fields'
EXEC('select * into '+#table+'_'+'convert(date, getdate()) from '+#table)
And I want the end result to look something like
template_fields_09-09-2015
What am I missing here?
Just print what you do:
DECLARE #table NVARCHAR(MAX) = 'tab';
DECLARE #sql NVARCHAR(MAX) = 'select * into '+#table+'_'
+'convert(date, getdate()) from '+#table;
SELECT #sql;
you will get: select * into tab_convert(date, getdate()) from tab
You need to pass date with table name like:
SqlFiddleDemo
DECLARE #table NVARCHAR(MAX) = 'tab';
DECLARE #new_table NVARCHAR(MAX) = #table + '_' +
CONVERT(NVARCHAR(100), GETDATE(),105);
DECLARE #sql NVARCHAR(MAX) = 'select * into ' + #new_table + ' from '+ #table;
SELECT #sql;
/* Result select * into tab_09-09-2015 from tab */
-- EXEC(#sql);
First of all, do not use EXEC to run dynamic queries, use sp_executesql instead.
Second: When you want to build a SQL query with variable object names, use QUOTENAME().
DECLARE #table sys.sysname = 'mytable'
DECLARE #backup sys.sysname = #table + '_' + CONVERT(date, GETDATE());
DECLARE #sql NVARCHAR(MAX) = 'SELECT * INTO '
+ QUOTENAME(#backup) + ' '
+ FROM + ' '
+ QUOTENAME(#table);
EXEC sp_executesql
#stmt = #sql
Please note that, the sys.sysname is a built in data type (essentially an alias for NVARCHAR(128) NOT NULL) and SQL Server uses it internally for object names.
Note: I have no SQL Server instance accessible right now, so the above query can contain typos.
I ended up resolving this myself. While some nice responses were added I wrote my initial query more simply to achieve this. Thank you all for the help.
--Declare and initiate the table
declare #table varchar(36)= 'template_fields'
--Declare and initiate the date (YYYYMMDD) without dashes
declare #date varchar(10) = convert(int, convert(varchar(10), getdate(), 112))
--Execute the query with the variables resulting in a new table titled 'template_fields_20150909'
EXEC('select * into '+#table+'_'+#date+' from '+#table)

Resources