[英]SQL Server stored procedure - invalid column name
我在 C# 中创建了一个临时表,从文件中填充它,然后(在 C# 中使用SqlCommand
)运行MyStoredProcedure
,它在将数据添加到数据库表之前清理和验证数据。
每次创建的临时表都略有不同,因为我只声明文件中存在的列,因此每次根据输入都有不同的字段。 存储过程通过在如下语句中运行每个验证来处理它:
IF EXISTS(SELECT 1 FROM sys.columns WHERE Object_ID = Object_ID(N'stagingTable') AND Name = N'FirstName')
BEGIN
UPDATE stagingTable
SET errors = ISNULL(errors, '') + 'First name column is blank.'
WHERE NULLIF(FirstName, '') IS NULL
UPDATE stagingTable
SET FirstName = UPPER(FirstName)
END
为了第一次编译和运行存储过程(即当我正在处理它时),我删除stagingTable
并使用所有可能的列创建它,然后运行一次MyStoredProcedure
。 在那之后,即使我删除stagingTable
并重新创建它并忽略一些列, MyStoredProcedure
仍然成功运行 - 假设这是因为它编译一次并且 IF 语句正在执行它们的工作。
但是,如果我尝试从 C# 应用程序执行此操作,则会引发异常
无效的列名
在当前版本的stagingTable
不存在的列上。 这看起来很奇怪 - 它在 SQL Server Management Studio 中运行时会忽略缺少的列名,只要它在更改后第一次成功编译即可。
但是从 C# 来看,它似乎正在运行一个新版本并检查每个列名,因此给出了“无效的列名”错误。
为什么它会在 SSMS 中正常运行,忽略由于 if 导致的无效列,并在从 C# 运行时调用此错误? 我不理解的关于编译的一些基本知识?
正如您所说,C# 和 SSMS 之间的行为不同,这很奇怪。 如果在服务器解析查询时该列不存在,我实际上希望它总是失败。
我假设如果您在临时表的“干净”版本上删除并重新创建存储过程,它会在 SSMS 中运行时失败吗?
绕过编译器的一种方法是将 SQL 的“动态”位作为动态 sql 运行。
EXEC sp_executesql N'update stagingTable set FirstName = upper(FirstName)'
不过,这只是最后的手段,并不能解释为什么您会看到两种环境之间的差异。
是的,这是一种已知行为。 当一个行源(表或视图)被引用但作为一个整体缺失时,解析器会容忍它; 当表或视图确实存在但缺少语句中任何位置引用的列时,它将因错误而中止。 没有干净的方法可以只为条件语句的一部分打开延迟名称解析。 确实存在一些技巧; 是否值得多走一英里,或者只是使用动态(文字)命令,这是一个意见问题:
将条件部分提取到存储过程中并进行调整,直到它提交: https : //stackoverflow.com/a/4315884/1132334
与此问题相关的已知方法摘要: https : //dba.stackexchange.com/a/24842/114522
安全回家:
使用EXEC('command-as-a-string')
语法作为解决方法,对于EXISTS
子句中的部分,将其中的任何单引号加倍:
IF EXISTS(SELECT 1 from sys.columns where Object_ID = Object_ID(N'stagingTable') AND [Name] = N'FirstName')
BEGIN
EXEC('
UPDATE stagingTable SET errors = ISNULL(errors, '''') + ''First name column is blank.'' WHERE NULLIF(FirstName, '''') IS NULL
UPDATE stagingTable SET FirstName = UPPER(FirstName)
')
END
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.