2008-09-23 5 views
5

Ich schrieb ein (scheinbar) unkompliziertes SQL-Snippet, das eine Spalte löscht, nachdem sichergestellt wurde, dass die Spalte existiert.
Das Problem: Wenn die Spalte nicht existiert, der Code innerhalb die IF-Klausel beschwert, dass es die Spalte nicht finden kann! Nun, doh, deshalb ist es in der IF-Klausel!
Also meine Frage ist, warum gibt ein Stück Code, der nicht ausgeführt werden sollte, Fehler?Warum gibt ein T-SQL-Block einen Fehler, selbst wenn er nicht einmal ausgeführt werden sollte?

Hier ist der Code-Schnipsel:

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 

... und hier ist der Fehler:

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

Ich bin mit Microsoft SQL Server 2005 Express Edition.

Antwort

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 

Grund: Wenn SQL Server den Code kompiliert, überprüfen sie es für gebrauchte Objekte (wenn sie existiert) . Diese Prüfprozedur ignoriert alle Konstrukte "IF", "WHILE" usw. und überprüft einfach alle verwendeten Objekte im Code.

+0

Korrekt. Sie erhalten diesen Fehler auch, wenn temporäre Tabellen herumliegen, die der Sproc verwendet. – ConcernedOfTunbridgeWells

+0

Um zu klären, ob eine temporäre Tabelle existiert, werden die Spalten überprüft, wenn Sie den Sproc kompilieren. Wenn der Sproc die Tabelle tatsächlich erstellt (z. B. mit einer Auswahl in), müssen Sie möglicherweise die Tabelle löschen, bevor Sie den Sproc neu kompilieren. – ConcernedOfTunbridgeWells

+0

Das ist eine sehr gute Antwort :) –

0

Es kann nie ausgeführt werden, aber es wird für die Gültigkeit von Sql Server analysiert. Der einzige Weg zu „umgehen“ Dies ist ein Block von dynamischen SQL zu konstruieren und dann selektiv

ausführen
0

Hier ist, wie ich es an die Arbeit:

Innerhalb der IF-Klausel, änderte ich den ALTER ... DROP ... Befehl mit exec ('ALTER ... DROP ...')

Es scheint, der SQL Server eine Gültigkeitsprüfung auf dem Code macht, wenn es das Parsen und sieht dass eine nicht existierende Spalte irgendwo referenziert wird (selbst wenn dieser Teil des Codes nie ausgeführt wird).
Mit dem Befehl exec(ute) wird der problematische Code in eine Zeichenfolge eingeschlossen, der Parser beschwert sich nicht und der Code wird nur bei Bedarf ausgeführt. Hier ist der modifizierte Code-Schnipsel:

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

By the way, gibt es ein ähnliches Problem in Oracle, und eine ähnliche Problemumgehung der "execute immediate" Klausel.

Verwandte Themen