为什么即使不应该执行,T-SQL块也会给出错误?
时间:2020-03-06 14:35:56 来源:igfitidea点击:
我正在编写一个(貌似)简单明了的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
...这是错误:
`执行SQL脚本[...]时出错。无效的列名"超时"
我正在使用Microsoft SQL Server 2005 Express Edition。
解决方案
它可能永远不会执行,但是它会被Sql Server解析以确保有效性。 "解决"的唯一方法是构造一个动态sql块,然后有选择地执行它
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"等构造,并仅检查代码中所有使用的对象。
这是我如何使其工作的方法:
在IF子句中,我用exec('ALTER ... DROP ...')更改了
ALTER ... DROP ...`命令。
似乎SQL Server在解析代码时会对代码进行有效性检查,并发现不存在的列在某处被引用(即使该代码段将永远不会执行)。
使用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
顺便说一句,Oracle中有一个类似的问题,并且使用"立即执行"子句也有一个类似的解决方法。