2008-09-23 8 views
5

Tôi đã viết một đoạn mã SQL (dường như) thẳng về phía trước để giảm một cột sau khi nó đảm bảo cột tồn tại.
Vấn đề: nếu cột KHÔNG tồn tại, mã bên trong mệnh đề IF than phiền rằng nó không thể tìm thấy cột! Vâng, doh, đó là lý do tại sao nó nằm trong mệnh đề IF!
Vì vậy, câu hỏi của tôi là, tại sao một đoạn mã không nên được thực hiện cho lỗi?Tại sao một khối T-SQL đưa ra một lỗi ngay cả khi nó thậm chí không nên được thực hiện?

Sau đây là đoạn:

IF exists (select * from syscolumns 
    WHERE id=object_id('Table_MD') and name='timeout') 
BEGIN 
    ALTER TABLE [dbo].[Table_MD] 
     DROP COLUMN timeout 
END 
GO 

... và đây là lỗi:

Error executing SQL script [...]. Invalid column name 'timeout'

Tôi đang sử dụng Microsoft SQL Server 2005 Express Edition.

Trả lời

10
IF exists (select * from syscolumns 
    WHERE id=object_id('Table_MD') and name='timeout') 
BEGIN 
    DECLARE @SQL nvarchar(1000) 
    SET @SQL = N'ALTER TABLE [dbo].[Table_MD] DROP COLUMN timeout' 
    EXEC sp_executesql @SQL 
END 
GO 

Lý do: Khi Sql server biên dịch mã, họ kiểm tra xem nó cho các đối tượng sử dụng (nếu họ tồn tại) . Thủ tục kiểm tra này bỏ qua bất kỳ "IF", "WHILE", vv ... cấu trúc và chỉ cần kiểm tra tất cả các đối tượng được sử dụng trong mã.

+0

Đúng. Bạn cũng sẽ nhận được lỗi này nếu có các bảng tạm thời nằm xung quanh mà sproc sử dụng. – ConcernedOfTunbridgeWells

+0

Để làm rõ, nếu một bảng tạm thời tồn tại thì các cột sẽ được kiểm tra khi bạn biên dịch sproc. Trường hợp sproc thực sự tạo bảng (ví dụ với một lựa chọn vào), bạn có thể cần phải thả bảng trước khi biên dịch lại sproc. – ConcernedOfTunbridgeWells

+0

Đây là câu trả lời rất hay :) –

0

Nó có thể không bao giờ được thực hiện, nhưng nó được phân tích cú pháp để hợp lệ bởi Sql Server. Cách duy nhất để "có được xung quanh" này là xây dựng một khối sql năng động và sau đó chọn lọc thực hiện nó

0

Đây là cách tôi đã nhận nó để làm việc:

Bên trong mệnh đề IF, tôi đã thay đổi lệnh ALTER ... DROP ... với exec ('ALTER ... DROP ...')

Có vẻ như máy chủ SQL sẽ kiểm tra tính hợp lệ trên mã khi phân tích nó, và thấy rằng một cột không tồn tại được tham chiếu ở đâu đó (ngay cả khi đoạn mã đó sẽ không bao giờ được thực thi).
Sử dụng lệnh exec(ute) bao bọc mã có vấn đề trong chuỗi, trình phân tích cú pháp không phàn nàn và mã chỉ được thực thi khi cần. Sau đây là đoạn chỉnh sửa:

IF exists (select * from syscolumns 
    WHERE id=object_id('Table_MD') and name='timeout') 
BEGIN 
    exec ('ALTER TABLE [dbo].[Table_MD] DROP COLUMN timeout') 
END 
GO 
0

Bằng cách này, có một vấn đề tương tự trong Oracle, và một cách giải quyết tương tự bằng cách sử dụng "thực hiện ngay lập tức" khoản.