Nombre de tabla como variable

171

Estoy tratando de ejecutar esta consulta:

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

Esto produce el siguiente error:

Mensaje 1087, Nivel 16, Estado 1, Línea 5

Debe declarar la variable de tabla "@tablename".

¿Cuál es la forma correcta de tener el nombre de la tabla poblado dinámicamente?

SoftwareGeek
fuente

Respuestas:

131

Para consultas estáticas, como la de su pregunta, los nombres de tabla y columna deben ser estáticos.

Para consultas dinámicas, debe generar el SQL completo dinámicamente y usar sp_executesql para ejecutarlo.

Aquí hay un ejemplo de un script utilizado para comparar datos entre las mismas tablas de diferentes bases de datos:

consulta estática:

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

Como quiero cambiar fácilmente el nombre de tabley schemahe creado 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

Dado que las consultas dinámicas tienen muchos detalles que deben considerarse y son difíciles de mantener, le recomiendo que lea: La maldición y las bendiciones del SQL dinámico

mdma
fuente
103

Cambie su última declaración a esto:

EXEC('SELECT * FROM ' + @tablename)

Así es como hago el mío en un procedimiento almacenado. El primer bloque declarará la variable y establecerá el nombre de la tabla en función del año actual y el nombre del mes, en este caso TEST_2012OCTOBER. Luego verifico si ya existe en la base de datos y elimino si es así. Luego, el siguiente bloque utilizará una instrucción SELECT INTO para crear la tabla y llenarla con registros de otra tabla con 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
fuente
Esta es la mejor respuesta.
ColinMac
Esta es la mejor respuesta porque es la más directamente aplicable al código existente del OP.
BH
37

Un poco tarde para una respuesta, pero debería ayudar a alguien más:

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
fuente
15
QUOTENAME es importante para la seguridad. Gracias.
Cihan Yakar
3
Pero, ¿cómo devolver el valor de dicha consulta? Por ejemplo COUNT(*)?
Suncatcher
35

No puede usar un nombre de tabla para una variable, en su lugar, debería hacer esto:

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

Tendrá que generar el sql dinámicamente:

declare @tablename varchar(50) 

set @tablename = 'test' 

declare @sql varchar(500)

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

exec (@sql)
Paul Kearney - pk
fuente
8

Se usa sp_executesqlpara ejecutar cualquier SQL, por ejemplo

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
fuente
Este ejemplo es muy útil.
Downhillski
0

Además, puedes usar esto ...

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
fuente
0
Declare  @tablename varchar(50) 
set @tablename = 'Your table Name' 
EXEC('select * from ' + @tablename)
usuario13581111
fuente
1
¡Bienvenido a Stack Overflow! Si bien este código puede resolver la pregunta, incluir una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación, y probablemente resultaría en más votos positivos. Recuerde que está respondiendo la pregunta para los lectores en el futuro, no solo la persona que pregunta ahora. Por favor, editar su respuesta para agregar explicaciones y dar una indicación de lo que se aplican limitaciones y supuestos. De la opinión
doble pitido
0

necesita usar el SQL dinámico de SQL Server

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

SET @table = N'tableName';

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

Use EXEC para ejecutar cualquier SQL

EXEC (@sql)

Use EXEC sp_executesql para ejecutar cualquier SQL

EXEC sp_executesql @sql;

Use EXECUTE sp_executesql para ejecutar cualquier SQL

EXECUTE sp_executesql @sql
Reza Jenabi
fuente
-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
fuente