SQL存储过程-无效的列名

问题描述 投票:1回答:2

我在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并使用所有可能的字段创建它,然后运行MytoredProcedure。之后,即使当我删除stagingTable并在不包含某些字段的情况下重新创建它时,MyStoredProcedure仍然可以成功运行-假定这是因为它只编译一次并且IF语句正在执行其工作。

但是,如果我尝试从C#应用程序执行此操作,则会在当前版本的stagingTable中不存在的字段上引发无效列名异常。这看起来很奇怪-只要它在更改后第一次成功编译,它就会在Management Studio中运行时忽略缺少的列名称。但是从C#来看,它似乎正在运行一个新版本并检查每个列名称,因此出现“无效的列名称错误”。

为什么它会在SSMS中正常运行,而忽略由于if导致的无效列,并从C#运行时调用此错误?我不了解的有关编译的基本知识吗?

c# asp.net sql-server
2个回答
0
投票

您声明,C#和SSMS的行为不同是很奇怪的。如果服务器在解析查询时该列不存在,我实际上希望它总是失败。

我假设如果您在暂存表的“干净”版本上删除并重新创建存储过程,则在SSMS中运行该存储过程会失败?

围绕编译器的一种方法是将SQL的“动态”位作为动态sql运行。

EXEC sp_executesql N'update stagingTable set FirstName = upper(FirstName)'

虽然这只是不得已,并且没有解释为什么您会看到两种环境之间的差异。


0
投票

是,这是已知的行为(相关:SQL Server reports 'Invalid column name', but the column is present and the query works through management studio

对于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 
© www.soinside.com 2019 - 2024. All rights reserved.