Must declare the scalar variable? - sql-server-2005

ALTER PROCEDURE selectedrfp
#from datetime,
#to datetime,
#bdename varchar(max),
#status int
AS
BEGIN
DECLARE #query varchar(max)
set #query='
SELECT RS.[RFP_ICode]
,RS.[Client_ICode]
,RS.[Client_Name]
,RS.[Project_Title]
,RS.[Client_Country]
,RS.[RFP_Technology]
,RS.[RFP_Received_Date]
,RS.[Cgvak_Comh_WishList]
FROM dbo.Cgvak_RFP_Status AS RS
INNER JOIN CGVAK_RFP_Status_Master AS RSM
ON RSM.[RFP_Status_Icode]=RS.[RFP_Status]
INNER JOIN CGVAK_RFP_Users AS RU
ON RU.[RFP_User_ICode]=RS.[BDE_Icode]
WHERE RS.[Cgvak_Comh_WishList]=1
AND RS.[RFP_Received_Date] BETWEEN #from AND #to
-- AND RS.[BDE_Name]=#bdename
AND RSM.[RFP_Status_ICode]=#status
AND RU.[RFP_User_Type] IN(1,2,3)'
DECLARE #withoutbde varchar(max)
SET #withoutbde='ORDER BY RS.[RFP_Received_Date] DESC'
DECLARE #withbde varchar(max)
SET #withbde='AND RS.[BDE_Name]=#bdename ORDER BY RS.[RFP_Received_Date] DESC'
IF(#bdename='All')
EXEC (#query + #withoutbde )
ELSE IF(#bdename!='All')
EXEC (#query + #withbde )
END
EXEC selectedrfp #from='2010/01/01',#to='2011/06/22',#bdename='chad',#status=4

The local variables #bdename etc are not in scope in the dynamic SQL.
You should use sp_executesql to parameterise them properly. Don't concatenate them.

Related

How to declare variables in T-SQL from select statements

declare #Week nvarchar(16) = quotename(concat('Week',#CID,#SID));
declare #Week2 nvarchar(256) = concat('SELECT TOP 1 [Year],[Week] FROM',#Week,'GROUP BY [Year],[Week] ORDER BY [Year] DESC,[Week] DESC');
exec sp_executesql #Week2
how can I declare #Year and #Week respectively from the result of exec sp_executesql #Week2? (declare as in assign the result values into #year and #week)
Thanks
declare #latestyear NVARCHAR(50), #latestweek NVARCHAR(50)
declare #Week2 nvarchar(256) = 'SELECT TOP 1 #latestyear=[Year],#latestweekweek=[Week] FROM [Week45] GROUP BY [Year],[Week] ORDER BY [Year] DESC,[Week] DESC';
exec sp_executesql #Week2
PRINT #latestyear
PRINT #latestweek
The above doesn't seem to work for me
Also trying to do this in 1 select statement if possible

Dynamic SQL output of a query to a variable

I would like to output the result of the dynamic SQL into a variable called #Count but not sure what the syntax or even the code should like to accomplish this.
The code looks as follows:
declare #tab nvarchar(255) = 'Person.person'
declare #Count int
declare #SQL nvarchar(max) = 'select count(*) from '+ #tab
exec(#SQl)
select #Count
thank you
Here's another way to do it that also safely addresses the SQL Injection isuues:
/* Counts the number of rows from any non-system Table, *SAFELY* */
-- The table name passed
DECLARE #PassedTableName as NVarchar(255) = 'Person.Person';
-- Make sure this isn't a SQL Injection attempt
DECLARE #ActualTableName AS NVarchar(255)
SELECT #ActualTableName = TABLE_SCHEMA + '.' + TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = PARSENAME(#PassedTableName,1)
AND TABLE_SCHEMA = PARSENAME(#PassedTableName,2)
-- make a temp table to hold the results
CREATE TABLE #tmp( cnt INT );
-- create the dynamic SQL
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'SELECT COUNT(*) FROM ' + #ActualTableName + ';'
-- execute it and store the output into the temp table
INSERT INTO #tmp( cnt )
EXEC(#SQL);
-- Now, finally, we can get it into a local variable
DECLARE #result AS INT;
SELECT #result = cnt FROM #tmp;
You can utilize sp_executesql to execute your count() query, and output it #Count.
Try this:
-- Set the table to count from
declare #tab nvarchar(255) = 'Person.person'
-- Assign the SQL query
declare #SQL nvarchar(255) = N'SELECT count(*) FROM ' + #tab
-- Pepare for sp_executesql
declare #Count int
declare #Params nvarchar(100) = N'#Count int output'
-- Set the count to #Count
exec sp_executesql #SQL, #Params, #Count=#Count output
-- Output #Count
select #Count
One last thing: Person.person looks like you might be trying to reference a person column from a Person table. But the above query is a literal representation of what it looks like you're trying to achieve in your question.
The below question is pretty much identical to what you are asking here.
sp_executeSql with output parameter
DECLARE #retval int
DECLARE #sSQL nvarchar(500);
DECLARE #ParmDefinition nvarchar(500);
DECLARE #tablename nvarchar(50)
SELECT #tablename = N'products'
SELECT #sSQL = N'SELECT #retvalOUT = MAX(ID) FROM ' + #tablename;
SET #ParmDefinition = N'#retvalOUT int OUTPUT';
EXEC sp_executesql #sSQL, #ParmDefinition, #retvalOUT=#retval OUTPUT;
SELECT #retval;

Assigning values returned by function in Dynamic SQL

I am trying to generate a dynamic SQL to assign variables with values from a function. I am trying to generate SQL something like
Select #StartDate=#EID_Dept
from dbo.WorkHistory(#today,#EID )
The function returns a date (#EID_dept will be the name of the column returned by the function) which I need to assign to #StartDate. And #EID_Dept is generated by concatenating #EID and #dept.
If I manually write the SQL it would appear as
Select #StartDate = amaan_IT
from dbo.WorkHistory('2016-10-10', amaan)
My code is below:
DECLARE #EID varchar(5), #StartDate VARCHAR(MAX),
#today DATETIME, #dept VARCHAR(10), #EID_dept varchar(20);
Select #today = SYSDATETIME()
Select #dept = dept from dbo.Dept(#EID)
Select #EID_Dept = CONCAT(#EID, #dept)
DECLARE #SQL Varchar(max);
SET #SQL = N'Select #StartDate = #EID_Dept
from dbo.PeriodHistory(#today, #EID)';
EXEC Sp_executesql
#SQL,
N'#StartDate VARCHAR(MAX) out,#EID_dept varchar(max),#today datetime,#EID Varchar',
#StartDate out,
#EID_Dept=#EID_Dept,
#today=#today
I changed your query a little bit. Hope this will work fine:
DECLARE #EID nvarchar(5),
#StartDate nvarchar(MAX),
#today datetime = SYSDATETIME(),
#dept nvarchar(10),
#EID_dept nvarchar(20),
#SQL nvarchar(max),
#params nvarchar(max) = N'#StartDate nvarchar(MAX) out, #today datetime, #EID nvarchar(5)'
Select #dept = dept from dbo.Dept(#EID)
Select #EID_Dept = CONCAT(#EID, #dept)
SET #SQL = N'Select #StartDate = ' + QUOTENAME(#EID_dept) + ' from dbo.PeriodHistory(#today, #EID);';
EXEC sp_executesql #SQL,
#params,
#StartDate = #StartDate out,
#today = #today,
#EID = #EID
SELECT #StartDate
I used nvarchar(max) for #SQL (you are using varchar but adding N when assign value to variable). sp_executesql awaits nvarchar in statement part
Is a Unicode string that contains a Transact-SQL statement or batch.
All parameters I put in #params variable.
As I understood you need to get another columns based on #EID_dept, so I add QUOTENAME and used this variable in SQL statement building directly. You can not send column name as variable.

Dynamic SQL Server stored procedure with table name as input param

I have the following stored procedure
CREATE PROCEDURE [dbo].[Insert]
#Service varchar(max),
#TableName varchar(100),
#Query varchar(250),
#Results varchar(max),
#CreatedDate datetime,
#ExpirationDate datetime
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION
DECLARE #SQL NVARCHAR(MAX), #ParmDefinition NVARCHAR(MAX)
DECLARE #q1 VARCHAR(MAX), #rez1 VARCHAR(MAX),
#date1 DATETIME, #date2 DATETIME
DECLARE #tablename VARCHAR(MAX) = #Service + '.' + #TableName
SET #SQL = N'if not EXISTS (select #q from ' + #tablename + ' where Query = #q) insert into ' + #tablename + ' values(#q, #rez, #date1, #date2)'
SET #ParmDefinition = N'#q varchar(max), #rez varchar(max),
#date1 datetime, #date2 datetime'
EXECUTE sp_executeSQL -- Dynamic T-SQL
#SQL,
#ParmDefinition,
#q = #Query,
#rez = #Results,
#date1= #CreatedDate,
#date2 = #ExpirationDate
COMMIT TRANSACTION
END
When I try to execute it, it doesn't insert anything, 0 rows
If I execute the code without the stored procedure, like a single query it inserts
Am I missing something?
There are a lot of things you have done in your question which doesnt make any sense to me, Why do you need to declare all these variables inside your procedure.
Yes true you are using parametrised query to protect yourself against sql injection attack, yet you left a hole by concatenating the object names (Table and database name), yes you will need to concatenate them but you can use QUOTENAME() function around them passed parameters and enforce sql server to put square brackets around these parameters and force sql server to treat them as nothing else but object names.
And Selecting a variable in IF EXISTS not make much sense. Select 1 which returns true if a row is found with matching criteria , and if no row is found it will simply insert a row.
Only declare variables that needs to declared, otherwise this make it look like a mess and difficult to debug. As they say Keep it simple :)
Also use appropriate data types for your parameters, #Service I believe is your database name why does it need to be a VARCHAR(MAX) data type, use the data type specific to store Sql Server Object names SYSNAME.
CREATE PROCEDURE [dbo].[Insert]
#Service SYSNAME,
#TableName SYSNAME,
#Query varchar(250),
#Results varchar(max),
#CreatedDate datetime,
#ExpirationDate datetime
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION
DECLARE #SQL NVARCHAR(MAX), #ParmDefinition NVARCHAR(MAX)
SET #SQL = N'IF NOT EXISTS (select 1 from ' + QUOTENAME(#Service) + '.' + QUOTENAME(#TableName)
+ N' where Query = #q) '
+ N'insert into ' + QUOTENAME(#Service) + '.' + QUOTENAME(#TableName)
+ N' values(#q, #rez, #date1, #date2)'
SET #ParmDefinition = N'#q varchar(250), #rez varchar(max),
#date1 datetime, #date2 datetime'
EXECUTE sp_executeSQL #SQL
,#ParmDefinition
,#q = #Query
,#rez = #Results
,#date1= #CreatedDate
,#date2 = #ExpirationDate
COMMIT TRANSACTION
END

Dynamic sql statement to update a variable

my sql statement is something like this below
DECLARE #OLD_NAV_VALUE AS INT
DECLARE #FINAL AS INT
SELECT #OLD_NAV_VALUE = [col1] from TBL_BA where DATE = #id_Date
SET #FINAL = #OLD_NAV_VALUE * 50
But the problem i am haveing here is that the column name in the select statement which is given as [col1] is a dynamic value. So i am trying something like this below.
DECLARE #OLD_NAV_VALUE AS INT
DECLARE #FINAL AS INT
EXEC('SELECT #OLD_NAV_VALUE = [' + #DYNAMIC_COL_NAME + '] from TBL_BA where DATE = ' + #id_Date)
SET #FINAL = #OLD_NAV_VALUE * 50
this gives an error that #OLD_NAV_VALUE has to be declared. So i tried declaring #OLD_NAV_VALUE inside the EXEC statement. But if i do this i am not able to use the same outside the EXEC statement.
Please let me know how to do this.
You can also use the sp_executesql statement with an output parameter:
declare #field nvarchar(50);
set #field = N'FieldToSelect';
declare #sql nvarchar(3000);
declare #parmDefinition nvarchar(500);
SET #parmDefinition = N'#returnValueOUT nvarchar(50) OUTPUT';
set #sql = N'SELECT #ReturnValueOUT = ' + #Field + ' FROM [TableName] WHERE [SomeCondition]'
declare #returnValue nvarchar(50);
EXECUTE sp_executesql #sql, #parmDefinition, #returnValueOut = #returnValue OUTPUT;
SELECT #returnValue
First, I'd suggest that you do a Google on "Erland dynamic SQL" and read his white paper on the subject.
Your design is probably not the best if it requires that you use a dynamic column name like this.
The reason that you can't do what you're trying to do is that everything in the EXEC is entirely in its own scope. If you absolutely have to do it this way though then you could use a table (either a normal table, or a global temporary table) to store the value for use outside of the EXEC.
We've used sp_executesql. Here's another example of a parameterized record count:
DECLARE #sql AS nvarchar(MAX)
SET #sql = N'SELECT #RecordCount = COUNT(*) FROM [{#SchemaName}].[{#TableName}]'
SET #sql = REPLACE(#sql, '{#SchemaName}', #SchemaName)
SET #sql = REPLACE(#sql, '{#TableName}', #TableName)
DECLARE #RecordCount AS int
EXEC sp_executesql
#query = #sql,
#params = N'#RecordCount INT OUTPUT',
#RecordCount = #RecordCount OUTPUT
This worked for me.
I declared a temp table and used it to receive the values from the select statement.
Something like below.
declare #i int
declare #v int
create table #t (val int)
insert into #t
exec ('declare #i int set #i = 0 select #i+1')
select * from #t