2008-09-23 18 views
5

我正在編寫一個看似簡單的SQL代碼片段,它在確保列存在後刪除列。
問題:如果該列不存在,代碼內部 IF子句抱怨它找不到列!那麼,doh,這就是爲什麼它在IF子句內!
所以我的問題是,爲什麼不應該執行一段代碼給出錯誤?爲什麼即使它不應該被執行,T-SQL塊也會報錯?

這裏的片段:

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 

...這是錯誤:

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

我使用Microsoft SQL Server 2005 Express版本。

回答

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 

原因: 當SQL Server編譯代碼,他們檢查它使用的對象(如果存在的話) 。這個檢查過程將忽略任何「IF」,「WHILE」等...構造,並簡單地檢查代碼中所有使用的對象。

+0

正確。如果臨時表位於sproc使用的周圍,您也會得到此錯誤。 – ConcernedOfTunbridgeWells 2008-09-23 13:35:16

0

它可能永遠不會被執行,但它會被Sql Server解析爲有效性。爲「避開」的唯一途徑,這是構建動態SQL塊,然後有選擇地執行它

0

以下是我得到它的工作:

的IF子句中,我改變了ALTER ... DROP ...命令exec ('ALTER ... DROP ...')

看來解析時,它的SQL服務器執行的代碼有效性檢查,並認爲一個不存在的列在某處被引用(即使這段代碼永遠不會被執行)。
使用exec(ute)命令將有問題的代碼包裝在一個字符串中,解析器不會發出抱怨,代碼只在需要時纔會執行。 下面是修改的摘錄:

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

順便說一句,有在甲骨文類似的問題,並使用「立即執行」的條款類似的解決方法。

相關問題