Passing Variable Into OpenQUERY SQL Server 2016 - sql-server

EDIT: SQL Server Version
I'm trying to pass this variable into my open query using this guide from Microsoft: Link
I'm running into this error message "Statement(s) could not be prepared." Which I believe means something is wrong with the OpenQuery. I'm just not sure what is wrong.
Here's the code:
DECLARE #ticketid INT, #QLFD VARCHAR(8000)
SELECT #ticketid = '296272348'
SELECT #QLFD = 'SELECT
*
FROM
OPENQUERY(
[Server_name],''
SELECT
ticket_id
, QLFD_SPD_AMT
FROM [database].[dbo].[table]
WHERE ticket_id = #ticketid
'')'
EXEC (#QLFD)
Could you help me identify the error? I prefer to do it passing the whole query as one.
Thanks!
Edit:
After looking at suggestions made by #Larnu. I have adjusted my code to:
DECLARE #ticketid INT--, #QLFD NVARCHAR(Max)
SELECT #ticketid = '296272348'
DECLARE #QLFD NVARCHAR(Max) = 'SELECT
*
FROM
OPENQUERY(
[Server_name],''
SELECT
ticket_id
, QLFD_SPD_AMT
FROM [database].[dbo].[table]
WHERE ticket_id = QUOTENAME(#ticketid, '''''''')
'')';
EXEC (#QLFD);

As I mentioned, you can't parametrise a query with OPENQUERY you have safely inject the values.
Normally that would be with QUOTENAME or REPLACE, but you don't actually need to do that here, due to the value being a numerical data type, so you can just concatenate it in:
DECLARE #ticketid int = 296272348; --Don't wrap numerical datatypes with quotes.
DECLARE #SQL nvarchar(MAX),
#OpenQuery nvarchar(4000);
SET #OpenQuery = CONCAT(N'SELECT QLFD_SPD_AMT
FROM [database].[dbo].[table]
WHERE ticket_id = ',#ticketid,N';'); --As it's an int we dont need to quote
SET #SQL = CONCAT(N'SELECT #ticketid AS ticket_id, QLFD_SPD_AMT
FROM OPENQUERY([servername],N''',REPLACE(#OpenQuery,'''',''''''),N''');';
EXEC sys.sp_executesql #SQL, N'#ticketid int', #ticketid;

Related

select statement in a variable I need to out put to a temp table

I am sure this is easy but I have a select statement stored as a variable e.g. #statement contains a statement "select count(*) from table1" I need to execute this variable e.g. sp_executesql #statement but put the results in to a temp table, is this possible easily?
Thanks
You can create your temp table first, then use insert into ... exec...:
declare #statement nvarchar(max);
set #statement = 'select 1';
create table #temp (rc int);
insert into #temp (rc)
exec sp_executesql #statement;
select * from #temp;
rextester demo: http://rextester.com/WPDAZ22362
returns: 1
One way:
declare #statement nvarchar(max) = 'select count(*) from table1'
declare #sql nvarchar(max) = N'set #result = (' + #statement + ')'
declare #result int
exec sp_executesql #sql, N'#result int OUTPUT', #result=#result OUTPUT;
select #result;
select #result as count into #temp
Sorry to say I wasn't given all of the question, where in the select statement I posted it only returned 1 field but I have now been told that the count i.e. 1 field was just an example and I might need to return multiple fields so SqlZim response would not of worked I don't think as I wouldn't always know the number/name of columns. What I chose to do was the following :-
Declare #TempSQLStatement nvarchar(max)
SET #TempSQLStatement=REPLACE(#statement,' FROM ',' INTO ##temp FROM ');
EXEC sp_executesql #TempSQLStatement;
SELECT * from ##temp
Not sure how to award the answer as Alex's solution would work fine and I believe SqlZim would of posted something similar if I had posted the complete info in the first place, can admin assist?

sp_executesql with always true condition

i have been using dynamic queries in sql-server like:
declare #sql nvarchar (1000),#condition nvarchar(100)='';
set #sql=N'select * from tablename where (0=0)'+#condition+'';
exec(#sql)
by this i was able to get my result whether the #condition has any value or not.
But i got to know that sp_executesql is better then exec as it promote query plan reuse.
So, i tried my query with `sp_executesql,
set #sql =N'select * from dbo.testclient where (0=0) #condition'
exec sp_executesql #sql,N'#condition nvarchar(100)',#condition
but it failed with an error as
Incorrect syntax near '#condition'.
My problem is how can i make the above query to work with sp_executesql where the parameter #condition can be a condition or blank (' ') and what am i doing wrong.
When you use variables such as #condition in sp_executesql, it does not simply replace your variable in the sql string with the content of the variable.
What happens is that the variable is bound to the supplied value and the sql statement is untouched.
This all means that you need to create a full sql statement which uses variables if you want to leverage query plan reuse.
For example:
SET #byIDsql = 'select * from tableName where (0=0) and Id = #Id'
SET #byNameSQL = 'select * from tableName where (0=0) and FirstName = #FirstName'
Then you can use sp_executesql to supply the value of #id and #firstName and get query plan reuse.
exec sp_executesql #byIDsql, N'#ID INT', 15
Tested code,
DECLARE #Sql nvarchar(MAX)='',
#paramlist nvarchar(4000),
#id int=3
set #paramlist = N' #id1 int'
set #Sql='select * from test where id=#id1'
exec sp_executesql #Sql,#paramlist,#id
select #Sql

SQL set variable as the result of a query in a stored procedure

I am creating a stored procedure with a cursor and I need to store the quantity of a column into a variable.
SQL says that it cannot convert nvarchar into int
I have tried to use CONVERT, CAST and EXEC but couldn't make it work.
How can I solve this ?
DECLARE #FieldName nvarchar(255);
DECLARE #RequestCode Nvarchar(50);
DECLARE #ReqSQLQuantity nvarchar(max);
DECLARE #Quantity int;
Select #ReqSQLQuantity = concat('select count(*) From (select distinct [', #FieldName , '] from [report_' , #RequestCode , ']) as number')
Set #Quantity = (#ReqSQLQuantity)
Select #Quantity
Another a bit safer option would be to use sp_executesql stored procedure something like this....
DECLARE #FieldName nvarchar(255);
DECLARE #RequestCode Nvarchar(50);
DECLARE #ReqSQLQuantity nvarchar(max);
DECLARE #Quantity int, #tableName SYSNAME;
SET #tableName = N'report_' + #RequestCode
Select #ReqSQLQuantity = N' select #Quantity = count(*) '
+ N' From (select distinct ' + QUOTENAME(#FieldName)
+ N' from ' + QUOTENAME(#tableName) + N' ) as number'
Exec sp_executesql #ReqSQLQuantity
,N'#Quantity INT OUTPUT'
,#Quantity OUTPUT
Select #Quantity
Set #Quantite = (#ReqSQLQuantite)
This is not an evaluation, is an implicit conversion. From NVARCHAR to INT, and you are trying to convert a SQL query text into an INT, hence the error.
Also, you are assuming that results are the same as return values and can be assigned to variables. This is incorrect, SQL execution results are sent to the client. To capture a result, you must use a SELECT assign: SELECT #value =.... Trying to run #variable = EXEC(...) is not the same thing. Think at SELECT results the same way as a print in an app: a print sends some text to the console. If you run some pseudo-code like x = print('foo') then 'foo' was sent to the console, and x contains the value returned by print (whatever that is). Same with this pseudo-SQL, #x = EXEC('SELECT foo') will send foo to the client, and #x will some numeric value which is the value returned by EXEC (in a correct example one would have to use explicit RETURN statement to set it).
Overall, the code as posted has absolutely no need for capturing the value and returning it, it can simply execute the dynamic SQL and let the result be returned to client:
SET #sql = concat(N'SELECT count(*) FROM (SELECT ... FROM ...)');
exec sp_executesql #sql;

How to use variable as table name in select into statement?

I have a problem with treating table name as variable as I need to put the results to different table each month automatically (without using any advanced procedures to make this query dynamic). Can somebody help me to modify this code and make it work?
declare #exp_dte as date;
set #exp_dte='2015-12-31';
print (#exp_dte);
declare #tab_mth as nvarchar(max);
set #tab_mth=year(#exp_dte)*100+month(#exp_dte);
print (#tab_mth);
declare #tab_name as nvarchar(max)
set #tab_name='mis_anl.dbo.BIK_' + #tab_mth
print (#tab_name);
IF OBJECT_ID (N'#tab_name', N'U') IS NOT NULL
begin
drop table #tab_name
end
select distinct
*
into #tab_name
from table_x
You have to use dynamic SQL to set name at runtime:
DECLARE #exp_dte DATE = '2015-12-31';
DECLARE #tab_name SYSNAME = '[dbo].' + QUOTENAME('BIK_' + FORMAT(#exp_dte, 'yyyyMM'));
IF OBJECT_ID (#tab_name, N'U') IS NOT NULL
BEGIN
EXEC('DROP TABLE' + #tab_name);
END
DECLARE #sql NVARCHAR(MAX) = N'SELECT DISTINCT *
INTO #tab_name
FROM table_x';
SET #sql = REPLACE(#sql, '#tab_name', #tab_name);
EXEC [dbo].[sp_executesql] #sql;
LiveDemo
Remarks:
Try to be more conscise
You could use FORMAT to get yyyyMM (SQL Server 2012+)
Always QUOTENAME generated identifiers to avoid SQL Injection attacks
I strongly recommend to read The Curse and Blessings of Dynamic SQL especially CREATE TABLE #tbl.
use dynamic sql ,you cant user table names as variables
declare #exp_dte as date;
set #exp_dte='2015-12-31';
declare #tab_mth as nvarchar(max);
set #tab_mth=year(#exp_dte)*100+month(#exp_dte);
declare #tab_name as nvarchar(max)
set #tab_name='mis_anl.dbo.BIK_' + #tab_mth
declare #sql1 nvarchar(max)
set #sql1='drop table '+#tab_name;
IF exists(select 1 from information_schema.tables where table_name=#tab_name)
begin
exec(#sql1);
end
declare #sql nvarchar(max)
set #sql='
select distinct
*
into '+#tab_name+'
from table_x'
exec (#sql)

How can I get data back from a dynamic call to OPENROWSET?

One strange attribute of T-SQL's OPENROWSET() function is that it cannot accept parameters within the 'query' which it executes remotely. In order to get around this I guess you have to create a long string containing the OPENROWSET calls and the parametrized query.
Given this limitation, I'm trying to get this piece of code to work:
Declare #DataId int
Declare #RecordType varchar(50)
Declare #Filter varchar(50)
-- ...
SELECT TOP 1
#RecordType = recordType,
#DataId = DataId
FROM OPENROWSET('SQLNCLI',
'Server=MyServer;Trusted_Connection=yes;',
'SELECT recordType, DataId FROM MyDb..data_lookup
WHERE Filter = ''' + #Filter+'''')
This throws an error
Incorrect syntax near '+'
Right now, which makes sense given the restriction on OPENROWSET. But if I convert this to SQL string, won't I lose the ability to set #RecordType and #DataId from the results of the query?
Is there any syntactic sugar I can sprinkle on this to get around the restriction and make this work the way I want it to?
Here's some examples of building a string dynamically:
http://support.microsoft.com/kb/314520
You could insert into a table variable first, and then pull your values from there.
DECLARE #t TABLE (DataID int, RecordType varchar(50))
INSERT INTO #t
exec sp_executeSQL N'your OPENROWSERT query'
SELECT TOP 1 #DataID = DataID, #RecordType = RecordType
FROM #t
Thanks to #Stuart, here is the code that I finally went with:
Declare #DataId int
Declare #RecordType varchar(50)
Declare #Filter varchar(50)
Declare #query nvarchar(4000)
-- ...
select #query = N'select top 1 recordType, DataId
from openrowset(''SQLNCLI'',
''Server=MyServer;Trusted_Connection=yes;'',
''SELECT recordType, DataId from MyDb..data_lookup
where Filter = ''''' + #Filter+''''''')'
declare #t TABLE (recordType varchar(2), DataId int)
insert into #t
exec sp_executeSQL #Query
select top 1 #RecordType = recordType, #DataId = DataId
from #t

Resources