Tabellenname als Variable


171

Ich versuche diese Abfrage auszuführen:

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

Dies führt zu folgendem Fehler:

Meldung 1087, Ebene 16, Status 1, Zeile 5

Muss die Tabellenvariable "@tabellenname" deklarieren.

Was ist der richtige Weg, um den Tabellennamen dynamisch zu füllen?

Antworten:


131

Bei statischen Abfragen wie der in Ihrer Frage müssen Tabellennamen und Spaltennamen statisch sein.

Bei dynamischen Abfragen sollten Sie das vollständige SQL dynamisch generieren und es mit sp_executesql ausführen.

Hier ist ein Beispiel für ein Skript, mit dem Daten zwischen denselben Tabellen verschiedener Datenbanken verglichen werden:

statische Abfrage:

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

da ich den Namen von leicht ändern möchte tableund schemadiese dynamische Abfrage erstellt habe:

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

Da dynamische Abfragen viele Details enthalten, die berücksichtigt werden müssen und schwer zu pflegen sind, empfehle ich Ihnen, Folgendes zu lesen: Der Fluch und der Segen von dynamischem SQL


103

Ändern Sie Ihre letzte Aussage in folgende:

EXEC('SELECT * FROM ' + @tablename)

So mache ich meine in einer gespeicherten Prozedur. Der erste Block deklariert die Variable und legt den Tabellennamen basierend auf dem aktuellen Jahr- und Monatsnamen fest, in diesem Fall TEST_2012OCTOBER. Ich überprüfe dann, ob es bereits in der Datenbank vorhanden ist, und entferne, wenn dies der Fall ist. Anschließend verwendet der nächste Block eine SELECT INTO-Anweisung, um die Tabelle zu erstellen und sie mit Datensätzen aus einer anderen Tabelle mit Parametern zu füllen.

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

Dies ist die beste Antwort.
ColinMac

Dies ist die beste Antwort, da sie am direktesten auf den vorhandenen Code des OP anwendbar ist.
BH

37

Etwas spät für eine Antwort, sollte aber jemand anderem helfen:

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 ist wichtig für die Sicherheit. Vielen Dank.
Cihan Yakar

3
Aber wie kann man einen Wert aus einer solchen Abfrage zurückgeben? ZB COUNT(*)?
Suncatcher

35

Sie können keinen Tabellennamen für eine Variable verwenden. Stattdessen müssen Sie Folgendes tun:

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

14

Sie müssen die SQL dynamisch generieren:

declare @tablename varchar(50) 

set @tablename = 'test' 

declare @sql varchar(500)

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

exec (@sql)

8

Verwenden Sie sp_executesqldiese Option, um SQL auszuführen, z

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

Dieses Beispiel ist sehr nützlich.
Downhillski

0

Sie können dies auch verwenden ...

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
Willkommen bei Stack Overflow! Während dieser Code die Frage lösen kann, einschließlich einer Erklärung, wie und warum dies das Problem löst, würde dies wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr Up-Votes führen. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten Sie Ihre Antwort, um Erklärungen hinzuzufügen und anzugeben, welche Einschränkungen und Annahmen gelten. Aus der Überprüfung
doppelter Piepton

0

Sie müssen das dynamische SQL Server-SQL verwenden

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

SET @table = N'tableName';

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

Verwenden Sie EXEC , um SQL auszuführen

EXEC (@sql)

Verwenden Sie EXEC sp_executesql , um SQL auszuführen

EXEC sp_executesql @sql;

Verwenden Sie EXECUTE sp_executesql , um SQL auszuführen

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.