Nome della tabella come variabile


171

Sto cercando di eseguire questa query:

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

Questo produce il seguente errore:

Messaggio 1087, livello 16, stato 1, riga 5

Deve dichiarare la variabile della tabella "@tablename".

Qual è il modo giusto per far popolare dinamicamente il nome della tabella?

Risposte:


131

Per le query statiche, come quella nella domanda, i nomi delle tabelle e delle colonne devono essere statici.

Per le query dinamiche è necessario generare SQL completo in modo dinamico e utilizzare sp_executesql per eseguirlo.

Ecco un esempio di uno script utilizzato per confrontare i dati tra le stesse tabelle di database diversi:

query statica:

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

poiché desidero facilmente cambiare il nome di tablee schemaho creato questa query dinamica:

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

Poiché le query dinamiche hanno molti dettagli che devono essere considerati e sono difficili da mantenere, ti consiglio di leggere: La maledizione e le benedizioni dell'SQL dinamico


103

Cambia la tua ultima affermazione in questo:

EXEC('SELECT * FROM ' + @tablename)

Ecco come faccio il mio in una Stored Procedure. Il primo blocco dichiarerà la variabile e imposterà il nome della tabella in base all'anno corrente e al nome del mese, in questo caso TEST_2012OCTOBER. Quindi controllo se esiste già nel DB e rimuovo se lo fa. Quindi il blocco successivo utilizzerà un'istruzione SELECT INTO per creare la tabella e popolarla con i record di un'altra tabella con parametri.

--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''')

Questa è la risposta migliore
ColinMac,

Questa è la risposta migliore perché è la più direttamente applicabile al codice esistente del PO.
BH,

37

Un po 'in ritardo per una risposta, ma dovrebbe aiutare qualcun altro:

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

15
QUOTENAME è importante per la sicurezza. Grazie.
Cihan Yakar,

3
Ma come restituire valore da tale query? Ad esempio COUNT(*)?
Suncatcher

35

Non puoi usare il nome di una tabella per una variabile, invece dovresti farlo:

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

14

Dovrai generare sql dinamicamente:

declare @tablename varchar(50) 

set @tablename = 'test' 

declare @sql varchar(500)

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

exec (@sql)

8

Utilizzare sp_executesqlper eseguire qualsiasi SQL, ad es

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

questo esempio è molto utile.
Downhillski,

0

Inoltre, puoi usare questo ...

DECLARE @SeqID varchar(150);
DECLARE @TableName varchar(150);  
SET @TableName = (Select TableName from Table);
SET @SeqID = 'SELECT NEXT VALUE FOR '+ @TableName + '_Data'
exec (@SeqID)

0
Declare  @tablename varchar(50) 
set @tablename = 'Your table Name' 
EXEC('select * from ' + @tablename)

1
Benvenuto in Stack Overflow! Sebbene questo codice possa risolvere la domanda, inclusa una spiegazione di come e perché questo risolva il problema, contribuirebbe davvero a migliorare la qualità del tuo post e probabilmente a dare più voti positivi. Ricorda che stai rispondendo alla domanda per i lettori in futuro, non solo per la persona che chiede ora. Si prega di modificare la risposta per aggiungere spiegazioni e dare un'indicazione di ciò si applicano le limitazioni e le assunzioni. Dalla recensione
Doppio segnale acustico

0

è necessario utilizzare l'SQL dinamico di SQL Server

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

SET @table = N'tableName';

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

Utilizzare EXEC per eseguire qualsiasi SQL

EXEC (@sql)

Utilizzare EXEC sp_executesql per eseguire qualsiasi SQL

EXEC sp_executesql @sql;

Utilizzare EXECUTE sp_executesql per eseguire qualsiasi SQL

EXECUTE sp_executesql @sql

-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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.