SQL Linked Server query with Parameters - sql

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.

Related

Error in dynamic execute with local variable

I'm getting the error :
Procedure expects parameter '#params' of type 'ntext/nchar/nvarchar'
for the following execute statement. I'm a little confused with this, after reading several posts on the website,
I came to understand that I would need to pass #val as a variable since exec will execute the command as-is.
declare #val varchar(max);
declare #query nvarchar(max);
set #query = 'set #val = (select ' + #cols + ' from temp where loan_number = ''72'')'
exec sp_executesql #query, '#val varchar(max) output', #val output
Conversely, if I executed the exec as a non-dynamic query as just exec(#query), I get the error
Must declare the scalar variable "#val".
IF the statement "Should the output of the query be a 1x1 table since I" is true, then you need to use a SELECT to set the value:
DECLARE #val varchar(MAX);
DECALRE #query nvarchar(MAX);
SET #query = N'SELECT #val = ' + QUOTENAME(#cols) + N' FROM temp WHERE loan_number = ''72'');';
EXEC sp_executesql #query, N'#val varchar(MAX) OUTPUT', #val OUTPUT;
The fact that you have a variable called #cols implies that the variable will hold the names of many columns, not one.

Dynamic Sp_Executesql failing on datetime conversion error

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

Concatenation problem in Dynamic sql query

I'm trying to concatenate the string with multiple variables and go for exec. Unfortunately I'm facing the conversion problem as:
Conversion failed when converting the varchar value 'Select #ExistingIds= CBSE_IX_J from ##tempPivot where EmployeeID=' to data type int.
My query is :
SET #ExecColumn = concat('Select #ExistingIds= '+#TSectionName +' from ##tempPivot where EmployeeID='+CAST(#TUserID as INT),'')
PRINT #ExecColumn
EXEC (#ExecColumn)
The "simple" answer is don't concatenate raw string values into your dynamic statement, and parametrise your code. This is a bit of guesswork, however, is far safer than the SQL Injection hole you have right now:
DECLARE #SQL nvarchar(MAX);
SET #SQL = N'SELECT #ExistingIDs = ' + QUOTENAME(#TSectionName) + NCHAR(13) + NCHAR(10)+
N'FROM ##tempPivot' + NCHAR(13) + NCHAR(10) +
N'WHERE EmployeeID = #TUserID;';
PRINT #SQL;
EXEC sp_executesql #SQL,
N'#TUserID int, #ExistingIds int OUTPUT', --guessed datatypes and that #ExistingIds is an OUTPUT
#TUserID = #TUserID,
#ExistingIds = ExistingIds OUTPUT;
Note: the fact that your variable is called #ExistingIDs implies you want to store multiple values in that variable. #ExistingIDs is a scalar value, it will only hold a scalar (single) value. If the query above returns multiple rows, only the value of from the last row will be returned. For example:
DECLARE #i int;
SELECT #i = I
FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9))V(I)
ORDER BY I;
SELECT #i;
Notice that #i has the value 9, not '1,2,3,...,9'.
You would seem to want:
DECLARE #SQL nvarchar(MAX);
DECALRE #ExistingIds NVARCHAR(MAX);
SET #SQL = N'
SELECT #ExistingIDs = STRING_AGG(#TSectionName, '''')
FROM ##tempPivot
WHERE EmployeeID = #TUserID
';
-- Cannot have identifiers as parameters, so use `REPLACE()`
SET #SQL = REPLACE(#SQL, '#TSectionName', QUOTENAME(#TSectionName);
EXEC sp_executesql #SQL,
N'#TUserID int, #ExistingIds NVARCHAR(MAX) OUTPUT', --guessed datatypes and that #ExistingIds is an OUTPUT
#TUserID=#TUserID,
#ExistingIds=#ExistingIds OUTPUT;
In older versions of SQL Server, you need another approach for concatenating strings. For instance
SET #SQL = N'
SELECT #ExistingIDs = (SELECT #TSectionName
FROM ##tempPivot
WHERE EmployeeID = #TUserID
FOR XML PATH ('')
)
';

How to Use Dynamic Sql on Update Command?

I Had Update Command. Just Like this.
Update DispatchExceptions
SET TYPE='MWM'
WHERE ID=9801246
I want to fire same command using dynamic sql.
DECLARE #ColumnName varchar(20)=N'TYPE'
DECLARE #ColumnValue char(3)='MWM'
DECLARE #ID INTEGER = 9801246
declare #Query nvarchar(max)
SET #Query = 'Update DispatchExceptions SET '+ QUOTENAME(#ColumnName) + '''=' + #ColumnValue + '''WHERE ID =' + #ID +''
EXEC (#Query)
But it show following error.
Conversion failed when converting the nvarchar value 'Update DispatchExceptions SET [TYPE]'=MWM'WHERE ID =' to data type int.
How can I use dynamic sql in the situation. Any suggestion.
The problem here is specifically the part ' + #ID. #ID is the datatype int, which has a higher datatype precedence than nvarchar; thus any other expressions will be implicitly cast to an int (and as I'm sure you're aware, 'Update DispatchExceptions SET...' isn't an int).
If you parametrise your query, you won't have this problem:
DECLARE #ColumnName sysname = N'TYPE'; --Changed the datatype here to sysname, as the caters for all possible object names
--sysname is actually a synonym for nvarchar(128), and 128 is the maximum length for an object's name
DECLARE #ColumnValue char(3) = 'MWM';
DECLARE #ID integer = 9801246;
DECLARE #Query nvarchar(MAX);
SET #Query = N'Update DispatchExceptions SET ' + QUOTENAME(#ColumnName) + N' = #value WHERE ID = #ID;';
EXEC sp_executesql #Query,
N'#Value char(3), #ID int',
#Value = #ColumnValue,
#ID = #ID;
Also, to the OP, well done on the use of QUOTENAME. This is far too often missed out, and thus leaves your (dynamic) SQL open to injection.
The DBMS fails to add
9801246
to
Update DispatchExceptions SET [TYPE]'=MWM'WHERE ID =
because the latter is a string and canot be converted to number, which would be necessary in order to add the number 9801246 to it :-)
One solution:
DECLARE #ID varchar(7) = '9801246'
Another solution:
SET #Query = 'Update DispatchExceptions SET '+ QUOTENAME(#ColumnName) +
'''=' + #ColumnValue + '''WHERE ID =' + CAST(#ID AS VARCHAR(7)) +''
Simply cast your #ID as varchar and correct quotation before #ColumnValue as given below:
SET #Query = 'Update DispatchExceptions SET '+QUOTENAME(#ColumnName)+'='''+#ColumnValue+''' WHERE ID ='+cast(#ID as varchar)+'';

Execute stored procedure using openrowset without doing with result sets for every column

When I execute a stored procedure using openrowset, which has dynamic SQL in it, it throws an error
Contains dynamic SQL. Consider using WITH RESULT SETS
An example is as follows.
select output.*
from openrowset ('SQLOLEDB','SERVER=(local);Trusted_Connection=yes;',
'SET FMTONLY OFF;SET NOCOUNT ON; exec storedproc ') as output
Since I have many output parameters, is there a simple way to display all the columns?
Note: I have to use openrowset as the stored procedure is being executed inside a script (R).
I also tried the following but didn't work.
declare #sqlstmt nvarchar(max)
declare #queryout nvarchar(max)
set #queryout = 'storedproc #parameter1=''''D'''', #param2=''''08/19/2018'''', '
set #queryout = '''exec ' + #queryout
set #sqlstmt = N'select outputprod.* from openrowset (''SQLOLEDB'',''SERVER=(local);Trusted_Connection=yes;'' , ' + #queryout + ''') as outputprod'
print(#sqlstmt)
exec (#sqlstmt)
You can use Dynamic Query with full select statement inside varchar variable then execute it with EXEC. see here.
for example
DECLARE #sqlCommand varchar(1000)
DECLARE #columnList varchar(75)
DECLARE #city varchar(75)
SET #columnList = 'CustomerID, ContactName, City'
SET #city = '''London'''
SET #sqlCommand = 'SELECT ' + #columnList + ' FROM customers WHERE City = ' + #city
EXEC (#sqlCommand)
Modify the Stored procedure with output parameter to return the generated query, to avoid dynamic stored procedure being passed.
DECLARE #queryout NVARCHAR(max)
DECLARE #sqlstmt NVARCHAR(max)
EXEC storedproc #queryout OUTPUT
SET #sqlstmt = N'SET FMTONLY OFF;SET NOCOUNT ON;' + #queryout
select output.* from openrowset (
'SQLOLEDB','SERVER=(local);Trusted_Connection=yes;', #sqlstmt) as output