I have a query like this:
DECLARE #TaskId UNIQUEIDENTIFIER
DECLARE #TaskName VARCHAR(255) = 'MasterSet'
DECLARE #sql NVARCHAR(MAX)
DECLARE #StartingDateTask DATETIME2 = (SELECT TOP 1 [Date]
FROM [TaskStatusAudit]
WHERE [TaskId] = 'A1FDFC16-904D-4560-B19D-5E7D4FEB1C2B'
AND [TaskStatusName] = 'IN-PROGRESS')
DECLARE #EndingDateTask DATETIME2 = (SELECT TOP 1 [Date]
FROM [TaskStatusAudit]
WHERE [TaskId] = 'A1FDFC16-904D-4560-B19D-5E7D4FEB1C2B'
AND [TaskStatusName] = 'COMPLETED')
SET #sql = N'SELECT dbo.TotalMinuteRange(#StartingDateTask,#EndingDateTask) as ' + quotename(#TaskName) + N''
EXEC sp_executesql #sql
Problem is when I execute it I get this error:
Must declare the scalar variable "#StartingDateTask".
Any ideas why I getting that if I declare my variable correctly? Regards
When executing sp_executesql you need to declare and pass the variables to sp_executesql something like..
SET #sql = N'SELECT dbo.TotalMinuteRange(#StartingDateTask,#EndingDateTask) as '
+ quotename(#TaskName) + N''
exec sp_executesql #sql
, N'#StartingDateTask DATETIME2 , #EndingDateTask DATETIME2'
, #StartingDateTask
, #EndingDateTask
Second parameter is the variable declaration parameter followed by the actual variables separately.
You can also do like taking a parameters variable and assign it.
declare #params nvarchar(100)
set #params='#StartingDateTask DATETIME2,#EndingDateTask DATETIME2'
SET #sql = N'SELECT dbo.TotalMinuteRange(#StartingDateTask,#EndingDateTask) as '
+ quotename(#TaskName) + N''
exec sp_executesql #sql
, #params
, #StartingDateTask
, #EndingDateTask
Related
I am writing a query which need to append the database name dynamically.
The query gets values from a table (in another database) , and I would interested to know if there is a better approach/way.
So my query looks like following :
DECLARE #TagNames AS VARCHAR(MAX) --Probably this is not a Global variable
DECLARE #QUERY AS VARCHAR(MAX)
SET #QUERY ='SELECT #TagNames = coalesce( #TagNames + '','','''') +
fldTagName FROM '+ dbo.fnGetZiConfigValue('KEYNAME')+'.dbo.tblTags Where
fldInterpolate = 1 AND fldUnitID = 13'
EXEC (#QUERY)
When I execute this , I get an error,
Must declare the scalar variable "#TagNames".
It is for sure not a global variable. You have to "declare" it inside dynamic SQL and return outside just like you'd do this with stored procedure.
DECLARE #TagNames AS VARCHAR(MAX) --Probably this is not a Global variable
DECLARE #QUERY AS NVARCHAR(MAX)
SET #QUERY = N'SELECT #TagNames = coalesce( #TagNames + '','','''') +
fldTagName FROM '+ QUOTENAME(dbo.fnGetZiConfigValue('KEYNAME'))+'.dbo.tblTags Where
fldInterpolate = 1 AND fldUnitID = 13'
exec sp_executesql #QUERY, N'#TagNames VARCHAR(MAX) OUTPUT', #TagNames OUTPUT
for sp_executesql dynamic sql and it's params declaration must be NVarchar.
I need to write a stored procedure which will return the value of a parameter, acquired from a Linked Server.
I have tried declaring the variable both inside and outside of the dynamic sql but it fails with a must declare variable error.
declare #srvr nvarchar(100)
declare #dbn nvarchar(50)
set #srvr = 'ServerName'
set #dbn = 'DatabaseName'
Declare #sql nvarchar(max)
set #sql = 'declare #param nvarchar(50) set #param = (Select X from [' + #srvr + '].[' + #dbn + '].[TableName])'
exec (#sql)
print #param
This will form the framework for multiple procedures which reside in a central database, these procedures will be called when restoring other databases into the environment forming part of 'prep script' of sorts
Any ideas please?
Thanks very much
You need to declare the variable twice. Once for the inner context, once for the outer context. They need not use the same names inside and out:
declare #srvr nvarchar(100)
declare #dbn nvarchar(50)
set #srvr = N'ServerName'
set #dbn = N'DatabaseName'
Declare #sql nvarchar(max)
declare #parms nvarchar(max)
set #sql = N'set #param = (Select X from [' + #srvr + '].[' + #dbn + '].[TableName])'
set #parms = N'#param nvarchar(50) output'
declare #param2 nvarchar(50)
exec sp_executesql #sql,#parms,#param = #param2 output
print #param2
I declared a variable #Obj and assign a complete table name 'ODS..Account' to it.
DECLARE #Obj VARCHAR(255)
Then I used it in a query immediately after FROM Clause. I perceive it is just a string, unable to act as a table object. So how can I fix the code to get it works? Cheers
INSERT Control.dbo.Consistency_Check
(Table_Name
,Schema_Name
,Id
,Incremental_DateTime_Column
)
SELECT
#Tab
,'ODS'
,Id
,SystemModstamp
FROM
#Obj )
You can use a local variable as a scalar value, not as a function. To do this, you need dynamic SQL:
declare #sql varchar(max);
select #sql = '
INSERT Control.dbo.Consistency_Check(Table_Name, Schema_Name, Id, Incremental_DateTime_Column)
SELECT ''#Tab'', 'ODS', Id, SystemModstamp
FROM #Tab
';
select #sql = replace(#sql, '#tab', #tab);
exec sp_executesql #sql;
Slightly different way of doing it with dynamic SQL:
DECLARE #Obj VARCHAR(255) = 'dbo.table'
DECLARE #SQL NVARCHAR(MAX) = ''
SET #SQL = #SQL +
'INSERT Control.dbo.Consistency_Check
(Table_Name
,Schema_Name
,Id
,Incremental_DateTime_Column
)
SELECT
#Tab
,''ODS''
,Id
,SystemModstamp
FROM
' + #Obj + ''
EXEC (#SQL)
You cannot. You probably want to use dynamic query. i.e. workout the SQL query string into a variable and exec using sp_executesql.
You may use the same variable name in the dynamic SQL but I changed it to #p_Tab for the example.
DECLARE #Tab int = 3
DECLARE #SQLString nvarchar(500)
DECLARE #ParmDefinition nvarchar(500) = N'#p_Tab int';
Declare #TableName nvarchar(100) = 'ODS..Account'
/* Build the SQL string dynamicly.*/
SET #SQLString = N'INSERT Control.dbo.Consistency_Check
(Table_Name
,Schema_Name
,Id
,Incremental_DateTime_Column
)
SELECT
#p_Tab
,''ODS''
,Id
,SystemModstamp
FROM
'+ #TableName
EXECUTE sp_executesql #SQLString, #ParmDefinition,
#p_Tab = #Tab
Further reference: https://msdn.microsoft.com/en-us/library/ms188001.aspx
I need to get data from a table in a database who's database name will be determined as a variable during a trigger. I then, knowing this variable need to get a seqno from a table in the determined database for a item which was also determined as a variable during a trigger.
I am trying this route as I assume I need to build the SQL statement before I set it to a variable.
This is not working and I need to know the best way on how I can do this:
DECLARE #SU_SEQNO INTEGER, #SU_NAME VARCHAR(50), #SU_OWNER VARCHAR(15), #SUD_SEQNO INTEGER, #SQL NVARCHAR(500)
SET #SU_OWNER = 'XXX'
SET #SU_NAME = '1ABC234'
SET #SQL ='SELECT #SUD_SEQNO=SEQNO FROM ' + (#SU_OWNER) + '.SU_MAIN
WHERE UNITNAME= ' + #SU_NAME
SET #SUD_SEQNO = (EXECUTE (#SQL))
Thanks alot for any help with this
From: Get result from dynamic SQL in stored procedure
SET #SQL = N'SELECT DISTINCT #FiscalYear = FiscalYear FROM ' + #DataSource;
EXEC sp_executesql #SQL, N'#FiscalYear INT OUTPUT', #FiscalYear OUTPUT;
PRINT #FiscalYear;
I'd re-engineer to use the sp_executesql method as shown above. That should do the trick.
I have amended the code, and it works
declare #su_owner varchar(15) = 'DBTEST'
declare #SU_SEQNO INTEGER=1, #SUD_SEQNO INTEGER=0, #SQL NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500), #SU_NAME_INPUT VARCHAR(50)='SU123'
SET #SU_NAME_INPUT = (SELECT UNITNAME FROM SU_MAIN WHERE SEQNO=#SU_SEQNO)
SET #SU_NAME = (SELECT UNITNAME FROM SU_MAIN WHERE SEQNO=#SU_SEQNO)
SET #SQL = N'SELECT #sud_seqnoOUT=MAX(SEQNO) FROM ' + quotename(#su_owner) + '.[dbo].[SU_MAIN] WHERE UNITNAME]=#SU_NAME_INPUT' ;
SET #ParmDefinition = N'#SU_NAME_INPUT VARCHAR(50),#sud_seqnoOUT INT OUTPUT'
EXEC sp_executesql #SQL,#ParmDefinition,#SU_NAME_INPUT = #SU_NAME,
#sud_seqnoOUT = #SUD_SEQNO OUTPUT
I am wondering why I cannot use variable column name like that:
declare #a as varchar;
set #a='TEST'
select #a from x;
Thank you
You can't do it because SQL is compiled before it knows what the value of #a is (I'm assuming in reality you would want #a to be some parameter and not hard coded like in your example).
Instead you can do this:
declare #a as varchar;
set #a='TEST'
declare #sql nvarchar(max)
set #sql = 'select [' + replace(#a, '''', '''''') + '] from x'
exec sp_executesql #sql
But be careful, this is a security vulnerability (sql-injection attacks) so shouldn't be done if you can't trust or well clean #a.
Because it is not allowed.
Insted of this you could use dynamic sql query:
declare #a as varchar;
set #a='TEST'
exec ('select ' + #a + ' from x')
Because the column names are resolved at compile time not at run time for the SQL statement.
use sp_executesql for this
Example
SET #SQLString = N'SELECT *
FROM table1
WHERE timet = #time and items in (#item)';
DECLARE #SQLString nvarchar(500);
DECLARE #ParmDefinition nvarchar(500);
SET #ParmDefinition = N'#time timestamp,
#item varchar(max) ';
EXECUTE sp_executesql
#SQLString
,#ParmDefinition
,#time = '2010-04-26 17:15:05.667'
,#item = '''Item1'',''Item2'',''Item3'',''Item4'''
;
If there are not too many columns to chose, how about a CASE WHEN statement?
DECLARE #ColName VARCHAR(50) = 'Test1'
SELECT [Foo], [Bar],
CASE
WHEN #ColName = 'Test1' THEN [Test1]
WHEN #ColName = 'Test2' THEN [Test2]
WHEN #ColName = 'Test3' THEN [Test3]
WHEN #ColName = 'Test4' THEN [Test4]
ELSE [TestDefault]
END [TestResult]
FROM [TableName];
This avoids using any EXEC.