我正在尝试执行此查询:
declare @tablename varchar(50)
set @tablename = 'test'
select * from @tablename

这会产生以下错误:

消息1087,级别16,状态1,第5行
必须声明该表变量“ @tablename”。

动态填充表名的正确方法是什么?

#1 楼

对于静态查询(例如您的问题),表名和列名必须是静态的。

对于动态查询,您应该动态生成完整的SQL,并使用sp_executesql来执行它。

这里是一个脚本示例,用于比较表中相同表之间的数据不同的数据库:

静态查询:

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


因为我想轻松更改tableschema的名称,所以我创建了此动态查询:

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


由于动态查询具有许多需要考虑的细节并且难以维护,因此我建议您阅读:动态SQL的诅咒和祝福

#2 楼

将您的最后一个声明更改为:

EXEC('SELECT * FROM ' + @tablename)


这就是我在存储过程中的工作方式。第一个块将声明变量,并根据当前的年和月名称设置表名,在本例中为TEST_2012OCTOBER。然后,我检查它是否已存在于数据库中,然后删除它是否存在。然后,下一个块将使用SELECT INTO语句创建表,并使用来自另一个表的带有参数的记录填充该表。

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


评论


这是最好的答案。

– ColinMac
2月11日,0:02

这是最佳答案,因为它最直接适用于OP的现有代码。

– B H
3月4日14:00

#3 楼

迟到了一个答案,但应该帮助别人:

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


评论


QUOTENAME对于安全性很重要。谢谢。

– Cihan Yakar
15年4月28日在10:05

但是如何从此类查询返回值?例如。 COUNT(*)吗?

–防晒
18年3月3日在9:57

@Suncatcher您可以具有输出参数或将其作为结果集返回。要显示如何将其读入变量,并且由于注释发布限制而不会在变量前加“ at”符号,请执行以下操作:声明nCount int Exec('从'+ sTableName中选择nCount = count(*))

– RowanPD
11月14日13:10

#4 楼

您不能为变量使用表名,而必须这样做:

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


#5 楼

您需要动态生成sql:

declare @tablename varchar(50) 

set @tablename = 'test' 

declare @sql varchar(500)

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

exec (@sql)


#6 楼

使用sp_executesql执行任何SQL,例如

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


评论


这个例子非常有用。

– Downhillski
18年4月5日在16:45

#7 楼

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


评论


欢迎使用Stack Overflow!尽管这段代码可以解决问题,但包括解释如何以及为什么解决该问题的说明,确实可以帮助提高您的帖子质量,并可能导致更多的投票。请记住,您将来会为读者回答问题,而不仅仅是现在问的人。请编辑您的答案以添加说明,并指出适用的限制和假设。来自评论

–双响
5月20日11:04

我喜欢这个答案的简单性,而且问题地址的三行相同。我认为不需要解释。谢谢。

–can.do
8月4日20:46

#8 楼

您需要使用SQL Server动态SQL

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

SET @table = N'tableName';

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



使用EXEC执行任何SQL

EXEC (@sql)


使用EXEC sp_executesql执行任何SQL

EXEC sp_executesql @sql;


使用EXECUTE sp_executesql执行任何SQL


#9 楼

另外,您可以使用此...

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


#10 楼

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