Tên bảng là biến


171

Tôi đang cố gắng thực hiện truy vấn này:

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

Điều này tạo ra lỗi sau:

Msg 1087, Cấp 16, Bang 1, Dòng 5

Phải khai báo biến bảng "@tablename".

Cách đúng để có tên bảng được điền động?

Câu trả lời:


131

Đối với các truy vấn tĩnh, như câu hỏi trong câu hỏi của bạn, tên bảng và tên cột cần phải tĩnh.

Đối với các truy vấn động, bạn nên tạo SQL đầy đủ một cách linh hoạt và sử dụng sp_executesql để thực thi nó.

Dưới đây là một ví dụ về tập lệnh được sử dụng để so sánh dữ liệu giữa các bảng của cùng một cơ sở dữ liệu khác nhau:

truy vấn tĩnh:

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

vì tôi muốn dễ dàng thay đổi tên của tableschematôi đã tạo truy vấn động này:

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

Vì các truy vấn động có nhiều chi tiết cần được xem xét và chúng khó có thể xác định được, tôi khuyên bạn nên đọc: Lời nguyền và phước lành của SQL động


103

Thay đổi tuyên bố cuối cùng của bạn thành này:

EXEC('SELECT * FROM ' + @tablename)

Đây là cách tôi thực hiện trong Thủ tục lưu trữ. Khối đầu tiên sẽ khai báo biến và đặt tên bảng dựa trên tên năm và tháng hiện tại, trong trường hợp này là TEST_2012OCTOBER. Sau đó tôi kiểm tra xem nó đã tồn tại trong DB chưa, và loại bỏ nếu có. Sau đó, khối tiếp theo sẽ sử dụng Câu lệnh CHỌN VÀO để tạo bảng và điền vào đó các bản ghi từ một bảng khác có tham số.

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

Đây là câu trả lời tốt nhất.
ColinMac

Đây là câu trả lời tốt nhất vì đây là câu trả lời trực tiếp nhất cho mã hiện có của OP.
BH

37

Hơi muộn cho một câu trả lời nhưng sẽ giúp đỡ người khác:

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 rất quan trọng đối với bảo mật. Cảm ơn.
Cihan Yakar

3
Nhưng làm thế nào để trả về giá trị từ truy vấn đó? Ví dụ COUNT(*)?
Suncatcher

35

Bạn không thể sử dụng tên bảng cho một biến, thay vào đó bạn phải làm điều này:

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

14

Bạn sẽ cần phải tạo sql động:

declare @tablename varchar(50) 

set @tablename = 'test' 

declare @sql varchar(500)

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

exec (@sql)

8

Sử dụng sp_executesqlđể thực thi bất kỳ SQL nào, vd

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

ví dụ này rất hữu ích
Downhillski

0

Ngoài ra, bạn có thể sử dụng ...

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
Chào mừng bạn đến với Stack Overflow! Mặc dù mã này có thể giải quyết câu hỏi, bao gồm giải thích về cách thức và lý do giải quyết vấn đề này thực sự sẽ giúp cải thiện chất lượng bài đăng của bạn và có thể dẫn đến nhiều lượt bình chọn hơn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, không chỉ người hỏi bây giờ. Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những hạn chế và giả định được áp dụng. Từ đánh giá
tiếng bíp đôi

0

bạn cần sử dụng SQL động SQL Server

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

SET @table = N'tableName';

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

Sử dụng EXEC để thực thi bất kỳ SQL nào

EXEC (@sql)

Sử dụng EXEC sp_executesql để thực thi bất kỳ SQL nào

EXEC sp_executesql @sql;

Sử dụng EXECUTE sp_executesql để thực thi bất kỳ SQL nào

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.