5

私は、列が存在することを確認した後に列をドロップする(一見)単純なSQLスニペットを書いていました。
問題:列が存在しない場合、 IF句のコードは、列が見つからないと文句を言います。そうですね、それがIF句の中にある理由です!
だから私の質問は、実行されるべきではないコードがなぜエラーを出すのかということです。

スニペットは次のとおりです。

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 2005ExpressEditionを使用しています。

4

4 に答える 4

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 サーバーがコードをコンパイルするとき、使用されているオブジェクト (存在する場合) をチェックします。このチェック手順は、「IF」、「WHILE」などの構造を無視し、コードで使用されているすべてのオブジェクトを単純にチェックします。

于 2008-09-23T13:28:21.727 に答える
0

実行されることはありませんが、SQL Server によって有効性が解析されます。これを「回避」する唯一の方法は、動的SQLのブロックを構築してから選択的に実行することです

于 2008-09-23T13:26:46.177 に答える
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
于 2008-09-23T13:42:02.550 に答える
0

ところで、Oracle にも同様の問題があり、"execute immediate" 句を使用した同様の回避策があります。

于 2008-09-23T14:06:07.453 に答える