2012-02-23 39 views
16

bất cứ ai có thể kiểm tra trên tuyên bố của tôi ...SQL Khai báo biến

DECLARE @tblName varchar(MAX), 
     @strSQL varchar(MAX) 

SET @tblName ='SELECT DISTINCT o.name as TableName 
       FROM sysobjects o 
       JOIN sysindexes x on o.id = x.id 
       WHERE o.name LIKE ''%empty%''' 

SET @strSQL = 'INSERT INTO @tblName VALUES(''trylng'', ''1'')' 
EXEC (@strSQL) 

lỗi của tôi là ...

Msg 1087, Level 15, State 2, Line 1
Phải khai báo biến bảng "@tblName".

+3

Tôi hy vọng chỉ có hai cột trong bất kỳ bảng nào được trả lại và kiểu dữ liệu phù hợp ... –

+0

@OMGPonies: Tất nhiên, bạn có nghĩa là cột có thể chèn. –

Trả lời

6

Không chắc chính xác những gì bạn đang cố gắng để làm, nhưng tôi nghĩ rằng bạn muốn một cái gì đó như thế này:

DECLARE @tblName varchar(MAX), @strSQL varchar(MAX) 
SET @tblName = 
    (select distinct o.name as TableName 
    from sysobjects o 
    join sysindexes x on o.id = x.id 
    where o.name LIKE '%empty%') 
SET @strSQL = 'INSERT INTO [' + @tblName + '] VALUES(''trylng'', ''1'')' 
exec (@strSQL) 

đó đang được nói, vẫn còn một vài điều cần xem ra cho đây. Bạn cần phải xử lý các điều kiện mà các SELECT DISTINCT trả về bất cứ điều gì khác hơn là một bản ghi duy nhất. Ngoài ra, tôi không thực sự hiểu nhu cầu xây dựng SQL động (trong @strSQL) khi @tblName sẽ luôn có cùng giá trị (vì không có biến nào được sử dụng trong mệnh đề WHERE).

+1

+1, chỉ có một lưu ý: thường là an toàn hơn khi kết hợp tên vào các tập lệnh động như sau: 'INSERT INTO '+ QUOTENAME (@tblName) +'… '', thay vì chỉ đơn giản là đặt dấu ngoặc vuông xung quanh chúng. –

+0

cảm ơn thông tin Andriy –

+0

@AndriyM: Tuyệt vời, cảm ơn mẹo! – rsbarro

12

tài sản @tblName của bạn tồn tại ở phạm vi bên ngoài - phạm vi của dòng mã "bình thường" của mình - nhưng không phải ở phạm vi bên trong của SQL bạn đang xây dựng trong chuỗi có ....

Bạn cần để thay đổi các dòng của bạn để đọc:

SET @strSQL = 'INSERT INTO ' + @tblName + ' VALUES(''trylng'', ''1'')' 

và sau đó nó sẽ hoạt động tốt. Ngoài ra, bạn không đề cập đến phiên bản SQL Server của bạn - nhưng kể từ SQL Server 2005 trở lên, bạn nên ngừng sử dụng sysobjectssysindexes - thay vào đó, hãy sử dụng lược đồ sys mới có chứa nhiều thông tin hơn - nhưng dễ dàng hơn. Thay đổi truy vấn của bạn để:

SET @tblName ='SELECT DISTINCT t.name as TableName 
       FROM sys.tables t 
       INNER JOIN sys.indexes i on i.object_id = t.object_id 
       WHERE t.name LIKE ''%empty%''' 

Xem MSDN: Querying the SQL Server System Catalog cho rất nhiều thông tin về những gì có sẵn trong sys schema mới và làm thế nào để tận dụng tối đa của nó!

Khi "rsbarro" được chỉ ra: đặt câu lệnh SQL này vào dấu ngoặc kép là lẻ - bạn có đang thực hiện câu lệnh này bằng cách sử dụng EXEC(...) không? Nhưng sau đó làm thế nào để bạn gán giá trị trở lại tài sản @tblName? Không thực sự có ý nghĩa .....

Nếu bạn muốn thực sự chạy truy vấn này để có được một giá trị, bạn nên có một cái gì đó như thế này:

SELECT TOP 1 @tblName = t.name 
FROM sys.tables t 
INNER JOIN sys.indexes i on i.object_id = t.object_id 
WHERE t.name LIKE '%empty%' 

Bạn cần có một TOP 1 trong đó được chắc chắn để chỉ nhận được một giá trị duy nhất - nếu không câu lệnh này có thể không thành công (nếu có nhiều hàng được chọn).

+0

Tôi có thiếu gì đó không? Tại sao @tblName được bao gồm trong dấu nháy đơn? Sẽ không chỉ cần thiết lập nó bằng chuỗi, và không phải là tên bảng? – rsbarro

+0

Không, ý tôi là tuyên bố thứ hai. Không nên đọc 'SET @tblName = SELECT DISTINCT t.name ...' không có dấu ngoặc kép? Cách nó được viết @strSQL sẽ có giá trị 'INSERT INTO SELECT DISTINCT t.Name là TableName ...'. Dường như với tôi rằng sẽ không hợp lệ, phải không? – rsbarro

+0

@rsbarro: ah ok - tốt, không chắc chắn - Tôi đã giả định OP sẽ thực thi câu lệnh SQL đó bằng cách sử dụng 'EXEC (....)'. Nếu không - thì bạn hoàn toàn đúng, nó sẽ không hoạt động! –