繁体   English   中英

SQL Server 存储过程 - 无效的列名

[英]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)'

不过,这只是最后的手段,并不能解释为什么您会看到两种环境之间的差异。

是的,这是一种已知行为。 当一个行源(表或视图)被引用但作为一个整体缺失时,解析器会容忍它; 当表或视图确实存在但缺少语句中任何位置引用的列时,它将因错误而中止。 没有干净的方法可以只为条件语句的一部分打开延迟名称解析。 确实存在一些技巧; 是否值得多走一英里,或者只是使用动态(文字)命令,这是一个意见问题:

安全回家:

使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM