Nome da tabela como variável

171

Estou tentando executar esta consulta:

declare @tablename varchar(50)
set @tablename = 'test'
select * from @tablename

Isso produz o seguinte erro:

Msg 1087, nível 16, estado 1, linha 5

É necessário declarar a variável da tabela "@tablename".

Qual é o caminho certo para que o nome da tabela seja preenchido dinamicamente?

SoftwareGeek
fonte

Respostas:

131

Para consultas estáticas, como a da sua pergunta, os nomes de tabelas e colunas precisam ser estáticos.

Para consultas dinâmicas, você deve gerar o SQL completo dinamicamente e usar sp_executesql para executá-lo.

Aqui está um exemplo de script usado para comparar dados entre as mesmas tabelas de bancos de dados diferentes:

consulta estática:

SELECT * FROM [DB_ONE].[dbo].[ACTY]
EXCEPT
SELECT * FROM [DB_TWO].[dbo].[ACTY]

desde que eu quero mudar facilmente o nome tablee schemacriei esta consulta dinâmica:

declare @schema varchar(50)
declare @table varchar(50)
declare @query nvarchar(500)

set @schema = 'dbo'
set @table = 'ACTY'

set @query = 'SELECT * FROM [DB_ONE].['+ @schema +'].[' + @table + '] EXCEPT SELECT * FROM [DB_TWO].['+ @schema +'].[' + @table + ']'

EXEC sp_executesql @query

Como as consultas dinâmicas têm muitos detalhes que precisam ser considerados e são difíceis de manter, recomendo que você leia: A maldição e as bênçãos do SQL dinâmico

mdma
fonte
103

Mude sua última declaração para esta:

EXEC('SELECT * FROM ' + @tablename)

É assim que eu faço o meu em um Procedimento Armazenado. O primeiro bloco declarará a variável e definirá o nome da tabela com base no nome atual do ano e mês, neste caso TEST_2012OCTOBER. Depois, verifico se ele já existe no banco de dados e removo. Em seguida, o próximo bloco usará uma instrução SELECT INTO para criar a tabela e preenchê-la com registros de outra tabela com parâmetros.

--DECLARE TABLE NAME VARIABLE DYNAMICALLY
DECLARE @table_name varchar(max)
SET @table_name = 
    (SELECT 'TEST_'
            + DATENAME(YEAR,GETDATE())
            + UPPER(DATENAME(MONTH,GETDATE())) )

--DROP THE TABLE IF IT ALREADY EXISTS
IF EXISTS(SELECT name 
          FROM sysobjects 
          WHERE name = @table_name AND xtype = 'U')

BEGIN
    EXEC('drop table ' +  @table_name)
END

--CREATES TABLE FROM DYNAMIC VARIABLE AND INSERTS ROWS FROM ANOTHER TABLE
EXEC('SELECT * INTO ' + @table_name + ' FROM dbo.MASTER WHERE STATUS_CD = ''A''')
Tim
fonte
Esta é a melhor resposta.
ColinMac
Essa é a melhor resposta, porque é a mais diretamente aplicável ao código existente do OP.
BH
37

Um pouco atrasado para uma resposta, mas deve ajudar outra pessoa:

CREATE PROCEDURE [dbo].[GetByName]
    @TableName NVARCHAR(100)
    AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    DECLARE @sSQL nvarchar(500);

    SELECT @sSQL = N'SELECT * FROM' + QUOTENAME(@TableName);

    EXEC sp_executesql @sSQL



END
Atul Chaudhary
fonte
15
QUOTENAME é importante para segurança. Obrigado.
Cihan Yakar
3
Mas como retornar valor dessa consulta? Por exemplo COUNT(*)?
Suncatcher
35

Você não pode usar um nome de tabela para uma variável, mas sim:

DECLARE @sqlCommand varchar(1000)
SET @sqlCommand = 'SELECT * from yourtable'
EXEC (@sqlCommand)
dcp
fonte
14

Você precisará gerar o sql dinamicamente:

declare @tablename varchar(50) 

set @tablename = 'test' 

declare @sql varchar(500)

set @sql = 'select * from ' + @tablename 

exec (@sql)
Paul Kearney - pk
fonte
8

Use sp_executesqlpara executar qualquer SQL, por exemplo

DECLARE @tbl    sysname,
        @sql    nvarchar(4000),
        @params nvarchar(4000),
        @count  int

DECLARE tblcur CURSOR STATIC LOCAL FOR
   SELECT object_name(id) FROM syscolumns WHERE name = 'LastUpdated'
   ORDER  BY 1
OPEN tblcur

WHILE 1 = 1
BEGIN
   FETCH tblcur INTO @tbl
   IF @@fetch_status <> 0
      BREAK

   SELECT @sql =
   N' SELECT @cnt = COUNT(*) FROM dbo.' + quotename(@tbl) +
   N' WHERE LastUpdated BETWEEN @fromdate AND ' +
   N'                           coalesce(@todate, ''99991231'')'
   SELECT @params = N'@fromdate datetime, ' +
                    N'@todate   datetime = NULL, ' +
                    N'@cnt      int      OUTPUT'
   EXEC sp_executesql @sql, @params, '20060101', @cnt = @count OUTPUT

   PRINT @tbl + ': ' + convert(varchar(10), @count) + ' modified rows.'
END

DEALLOCATE tblcur
ghgh
fonte
Este exemplo é muito útil.
Downhillski
0

Além disso, você pode usar isso ...

DECLARE @SeqID varchar(150);
DECLARE @TableName varchar(150);  
SET @TableName = (Select TableName from Table);
SET @SeqID = 'SELECT NEXT VALUE FOR '+ @TableName + '_Data'
exec (@SeqID)
Disha Sojitra
fonte
0
Declare  @tablename varchar(50) 
set @tablename = 'Your table Name' 
EXEC('select * from ' + @tablename)
user13581111
fonte
1
Bem-vindo ao Stack Overflow! Embora esse código possa resolver a questão, incluir uma explicação de como e por que isso resolve o problema realmente ajudaria a melhorar a qualidade da sua postagem e provavelmente resultaria em mais votos positivos. Lembre-se de que você está respondendo à pergunta dos leitores no futuro, não apenas à pessoa que está perguntando agora. Por favor edite sua resposta para adicionar explicações e dar uma indicação do que limitações e premissas se aplicam. Da avaliação
double-beep
0

você precisa usar o SQL dinâmico do SQL Server

DECLARE @table     NVARCHAR(128),
        @sql       NVARCHAR(MAX);

SET @table = N'tableName';

SET @sql = N'SELECT * FROM ' + @table;

Use EXEC para executar qualquer SQL

EXEC (@sql)

Use EXEC sp_executesql para executar qualquer SQL

EXEC sp_executesql @sql;

Use EXECUTE sp_executesql para executar qualquer SQL

EXECUTE sp_executesql @sql
Reza Jenabi
fonte
-1
Declare @fs_e int, @C_Tables CURSOR, @Table varchar(50)

SET @C_Tables = CURSOR FOR
        select name from sysobjects where OBJECTPROPERTY(id, N'IsUserTable') = 1 AND name like 'TR_%'
OPEN @C_Tables
FETCH @C_Tables INTO @Table
    SELECT @fs_e = sdec.fetch_Status FROM sys.dm_exec_cursors(0) as sdec where sdec.name = '@C_Tables'

WHILE ( @fs_e <> -1)
    BEGIN
        exec('Select * from '+ @Table)
        FETCH @C_Tables INTO @Table
        SELECT @fs_e = sdec.fetch_Status FROM sys.dm_exec_cursors(0) as sdec where sdec.name = '@C_Tables'
    END
Laurent
fonte