0

Been struggling with this one for a good while now. I'm trying to use sp_executesql below:

DECLARE @SQLString nvarchar(500);   
DECLARE @ParmDefinition nvarchar(500);  
DECLARE @IntVariable int;  
DECLARE @fulldbtablename nvarchar(500);  
DECLARE @ID bigint;  

SET @fulldbtablename = QUOTENAME(@databasename) + '.[DBO].' + QUOTENAME(@tablename)

SET @SQLString = N'SELECT TOP 1 @IDOut = ID FROM' + @fulldbtablename + 'WHERE LastModified < DATEADD(DAY, @daystokeep, GETDATE()) order by 1 desc';  
SET @ParmDefinition = N'@daystokeep int,  
@IDOut bigint OUTPUT';  
SET @IntVariable = -1; 

EXECUTE sp_executesql  
@SQLString  
,@ParmDefinition  
,@daystokeep = @IntVariable 
,@IDOut = @ID OUTPUT;

I'm getting the error Must declare the scalar variable "@ID"

I've reviewed the help below, but I can't shake this error. Has anyone any ideas? I am declaring @ID in DECLARE @ID bigint;

To help me debug, I split the query into a new window and ran the query below which completes successfully so I am pulling my hair out:

DECLARE @Databasename varchar(500)
DECLARE @Tablename varchar(500)
DECLARE @ID bigint;
DECLARE @SQLString nvarchar(500);  
DECLARE @ParmDefinition nvarchar(500);  
DECLARE @IntVariable int;  
DECLARE @fulldbtablename nvarchar(500); 

SET @databasename = 'DatabaseName'
Set @Tablename = 'TableName'
SET @fulldbtablename = QUOTENAME(@databasename) + '.[DBO].' + QUOTENAME(@tablename)

SET @SQLString = N'SELECT TOP 1 @IDOut = ID FROM' + @fulldbtablename + 'WHERE LastModified < DATEADD(DAY, @daystokeep, GETDATE()) order by 1 desc';  
SET @ParmDefinition = N'@daystokeep int,  
@IDOut bigint OUTPUT';  
SET @IntVariable = -1; 

EXECUTE sp_executesql  
@SQLString  
,@ParmDefinition  
,@daystokeep = @IntVariable 
,@IDOut = @ID OUTPUT;  

SELECT @ID

Anyone any ideas?????? Thank you!

5
  • 1
    Have you looked at using sp_executesql with an OUTPUT variable? learn.microsoft.com/en-us/sql/relational-databases/… Commented May 23, 2017 at 14:54
  • I did thanks Erik, but I couldn't make it stick with the dynamic table name and the SELECT TOP 1 (ID). I might just be being thick but I couldn't make it work. Commented May 23, 2017 at 14:56
  • Can you post the code you tried for that? Commented May 23, 2017 at 14:57
  • ` DECLARE @sqlcommand nvarchar(max) = 'SELECT TOP 1 (ID) from ' + @tablename + ' where LastModified < DATEADD(DAY,' + @NumberOfKeepDays + ', GETDATE()) order by 1 desc' execute sp_executesql @sqlcommand, N'@ID bigint OUTPUT', @ID = @ID output; ` Commented May 23, 2017 at 15:02
  • 1
    Please use QUOTENAME(@tablename) at the very least. You could also add checks to make sure @tablename exists, prefix it with the right schema, etc. I wrote a two-part tip on SQL injection here and here. Commented May 23, 2017 at 15:34

1 Answer 1

2

You were missing the variable assignment inside the dynamic SQL batch.

DECLARE @sqlcommand NVARCHAR(MAX) = 'SELECT TOP 1 @ID = (ID) --Assign me!
                                     FROM ' + QUOTENAME(@tablename) + ' 
                                     WHERE LastModified < DATEADD(DAY,' + @NumberOfKeepDays + ', GETDATE()) 
                                    ORDER BY 1 DESC';

EXECUTE sys.sp_executesql @sqlcommand, N'@ID BIGINT OUTPUT', @ID = @ID OUTPUT;

The example from the sp_executesql doc is pretty clear, though suffers from formatting.

DECLARE @SQLString nvarchar(500);  
DECLARE @ParmDefinition nvarchar(500);  
DECLARE @SalesOrderNumber nvarchar(25);  
DECLARE @IntVariable int;  

SET @SQLString = N'SELECT @SalesOrderOUT = MAX(SalesOrderNumber) --Assign me!
    FROM Sales.SalesOrderHeader  
    WHERE CustomerID = @CustomerID';  
SET @ParmDefinition = N'@CustomerID int,  
    @SalesOrderOUT nvarchar(25) OUTPUT';  
SET @IntVariable = 22276;  

EXECUTE sp_executesql  
    @SQLString  
    ,@ParmDefinition  
    ,@CustomerID = @IntVariable  
    ,@SalesOrderOUT = @SalesOrderNumber OUTPUT;  
-- This SELECT statement returns the value of the OUTPUT parameter.  
SELECT @SalesOrderNumber; 

If you want to learn a whole heck of a lot about dynamic SQL, SQL injection (and you should, because what you're executing now is potentially unsafe), head over here

10
  • I'm getting "Must declare the scalar variable "@ID", despite declaring it earlier in the script. I think it's to do with 'SELECT TOP 1 @ID = (ID) Commented May 23, 2017 at 15:50
  • @Stephen sorry to hear that, but without seeing it, I can't help you. I have @ID declared for the dynamic SQL in my example. Commented May 23, 2017 at 15:57
  • Thanks for helping Erik: ` DECLARE @sqlcommand NVARCHAR(MAX) = N'SELECT TOP 1 @ID = (ID) FROM ' + QUOTENAME(@tablename) + ' WHERE LastModified < DATEADD(DAY,' + CONVERT(varchar(20), @NumberOfKeepDays) + ', GETDATE()) ORDER BY 1 DESC'; EXECUTE sys.sp_executesql @sqlcommand, N'@ID BIGINT OUTPUT', @ID = @ID OUTPUT; SET @ID = CEILING(@ID/1000.0)*1000 Commented May 23, 2017 at 16:00
  • @Stephen you are not declaring @ID anywhere in that script. You have to do it both inside and outside of the dynamic SQL batch. If you want to add code, please update your question instead of pasting it in comments. Also, I'd urge you to look at example code from the links I posted. Commented May 23, 2017 at 16:04
  • sorry I'm not really helping myself. I've editing the question above which hopefully makes it clearer. Thanks for your help. Commented May 24, 2017 at 10:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.