20

I have a table variable in SQL Server 2008

    DECLARE @specsAndModel TABLE
    (
        specName VARCHAR(50)
        ,specVal VARCHAR(50)
    )
    INSERT INTO @specsAndModel
    VALUES('[modelNumber]', 'F00-B4R')

Then, I later build a string called @query, which I ultimately try to pass into EXECUTE, as in the following example:

    DECLARE @query NVARCHAR(MAX);
    SET @query = 'SELECT specName, specVal FROM @specsAndModel'
    EXECUTE(@query)

However, SQL Server gives me the error message: Must declare the table variable "@specsAndModel".

After searching around, I think this might be related to the execution context, but I haven't been able to resolve the problem.

Is it even possible for me to use a table variable in a call to the execute function?

tlehman
  • 5,125
  • 2
  • 33
  • 51

2 Answers2

24

The table you are creating is a table variable which is not available outside of its initial scope. There are a few ways to fix this:

Create a Global Temp Table (Disclaimer: this can cause problems if more that one user attempts to run this at the same time.):

create table  ##specsAndModel 
(
    specName VARCHAR(50)
    ,specVal VARCHAR(50)
)
INSERT INTO ##specsAndModel
VALUES('[modelNumber]', 'F00-B4R')

DECLARE @query NVARCHAR(MAX);
SET @query = 'SELECT specName, specVal FROM ##specsAndModel'
EXECUTE(@query)

Create a Local Temp Table instead of global:

create table  #specsAndModel 
(
    specName VARCHAR(50)
    ,specVal VARCHAR(50)
)
INSERT INTO #specsAndModel
VALUES('[modelNumber]', 'F00-B4R')

DECLARE @query NVARCHAR(MAX);
SET @query = 'SELECT specName, specVal FROM #specsAndModel'
EXECUTE(@query)

Execute the create table inside of your dynamic SQL (ugly):

DECLARE @query NVARCHAR(MAX);
SET @query = 'DECLARE @specsAndModel TABLE
(
    specName VARCHAR(50)
    ,specVal VARCHAR(50)
)
INSERT INTO @specsAndModel
VALUES(''[modelNumber]'', ''F00-B4R'')
SELECT specName, specVal FROM @specsAndModel'
exec(@query)

Instead of using a temp table, create an actual table and then drop it when done (Disclaimer: this can cause problems if more that one user attempts to run this at the same time.):

create TABLE specsAndModel 
(
    specName VARCHAR(50)
    ,specVal VARCHAR(50)
)
INSERT INTO specsAndModel
VALUES('[modelNumber]', 'F00-B4R')

DECLARE @query NVARCHAR(MAX);
SET @query = 'SELECT specName, specVal FROM specsAndModel'
EXECUTE(@query)  

drop table specsAndModel

Here is an link to a discussion about temp tables and table variables:

Should I use a #temp table or a @table variable?

Edit: You can pass in a table variable using sp_executesql:

create type specsAndModel as table (
    specName VARCHAR(50)
    ,specVal VARCHAR(50)
 )
go
declare @t specsAndModel
insert @t VALUES('[modelNumber]', 'F00-B4R')

exec sp_executesql N'select specName, specVal from @var', N'@var specsAndModel readonly', @t

Using either the global ##temp tables and a permanent table run risks in that if more than one users attempts to run the process, there could be conflicts.

You are safer using either a local #temp table or passing the table variable using sp_executesql.

Taryn
  • 242,637
  • 56
  • 362
  • 405
  • 1
    Actually, you can pass a table variable to `sp_executesql`, but you need to create a type for the variable. Take a look at this answer by Andomar: http://stackoverflow.com/a/7330410/519216 – Lamak Aug 21 '12 at 16:53
  • I would recommend against a global ##temp table (or a permanent table). Your first code sample works fine with a LOCAL #temp table and doesn't kill concurrency. P.S. I wrote the #temp / @table article you linked to. :-) – Aaron Bertrand Aug 21 '12 at 16:58
  • @Lamak updated my answer to include that process. I was not aware of it. – Taryn Aug 21 '12 at 16:58
  • I like the use of `sp_executesql` better too, I have to drop the global temp table every time I use it. – tlehman Aug 21 '12 at 16:59
  • @AaronBertrand my bad, I must have done something else when I tested the local #temp. I updated my answer to include that as well. I didn't know you wrote that article...but I am not surprised. – Taryn Aug 21 '12 at 17:01
  • 1
    I would take out the global and permanent table recommendations, or at least include a disclaimer about how these things will break if two users try to run this code at the same time. The #temp table and table variable methods don't have this problem. – Aaron Bertrand Aug 21 '12 at 17:06
2

You also have to create your table variable inside the in the string.

DECLARE @query NVARCHAR(MAX);
SET @query = 'DECLARE @specsAndModel TABLE  ( specName VARCHAR(50) ,specVal VARCHAR(50))'
SET @Query = @Query + ' INSERT INTO  @specsAndModel VALUES(''modelNumber'',''abcd''); SELECT specName, specVal FROM @specsAndModel'
EXEC (@query)
Waqar Janjua
  • 6,113
  • 2
  • 26
  • 36