即使检查列名是否存在,列名也无效,因此应该跳过查询部分

Mic*_*rst 3 sql-server query t-sql

我有以下查询:

    IF EXISTS( SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'NotificationTableLogRows' AND COLUMN_NAME = 'DestinationAddress') BEGIN  
      UPDATE NotificationTableLogRows
      SET [HandlerID] = m.ID
      FROM [Unicare].dbo.MobileDevices m
      WHERE HandlerID is null 
      AND m.CallNumber = NotificationTableLogRows.DestinationAddress AND NotificationTableLogRows.HandlerTypeID = 2
    END
print 'end'
Run Code Online (Sandbox Code Playgroud)

但运行后,我仍然收到错误:

Msg 207, Level 16, State 1, Line 6
Invalid column name 'DestinationAddress'.
Run Code Online (Sandbox Code Playgroud)

但是它应该只打印结束

我究竟做错了什么?

编辑:

即使:

IF 1 = 0 BEGIN
    UPDATE NotificationTableLogRows
    SET [HandlerID] = m.ID
    FROM [Unicare].dbo.MobileDevices m
    WHERE HandlerID is null 
    AND m.CallNumber = NotificationTableLogRows.DestinationAddress AND NotificationTableLogRows.HandlerTypeID = 2
END
Run Code Online (Sandbox Code Playgroud)

它产生相同的错误,问题似乎出在 sql 检查预执行查询的方式上。

Aar*_*and 6

这是解析时错误,而不是运行时错误。您不能使用IF检查来确定列引用是否可以使用,因为列引用首先在运行之前进行验证IF(这就是为什么IF 1 = 0也会失败)。

注意:如果您将脚本复制到您自己的系统(其中不存在这些对象) ,问题中的脚本似乎可以工作(例如,它将打印)。由于延迟名称解析,如果任何对象尚不存在,则解析检查将成功,但如果所有对象存在,但任何列不存在,则解析检查将失败。end

作为证明,比较:

IF 1 = 0
BEGIN
  SELECT 1 FROM sys.columns AS c
    INNER JOIN sys.objects AS o
    ON c.blat = o.splunge;
END
GO

/* 
  Msg 207, Level 16, State 1
  Invalid column name 'blat'.
  Msg 207, Level 16, State 1
  Invalid column name 'splunge'.
*/

IF 1 = 0
BEGIN
  SELECT 1 FROM dbo.blats AS b
    INNER JOIN dbo.splunges AS s
    ON b.blat = s.splunge;
END
GO

/* 
  "success" 
*/
Run Code Online (Sandbox Code Playgroud)

现在创建一个名为 的表dbo.blats,但没有名为 的列blat

CREATE TABLE dbo.blats(id int);
Run Code Online (Sandbox Code Playgroud)

第二个脚本仍然成功,因为仍然有一个对象尚不存在,并且 SQL Server 为您提供了怀疑的好处 - 至少在解析时 - 您将在执行脚本之前创建它。dbo.splunges当您添加第二个表 ,但没有引用的列时,它将失败splunge

CREATE TABLE dbo.splunges(id int);
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,您可以使用这个麻烦的解决方法,或者只使用动态 SQL(这里我使用sys.columns 而不是INFORMATION_SCHEMA,嗯,因为):

IF EXISTS 
(
  SELECT 1 
    FROM sys.columns AS c 
    INNER JOIN sys.objects AS o
      ON o.[object_id] = c.[object_id]
    INNER JOIN sys.schemas AS s
      ON o.[schema_id] = s.[schema_id]
    WHERE s.name = N'schema_name'
      AND o.name = N'object_name'
      AND c.name = N'column_name'
)
BEGIN
  EXEC sys.sp_executesql N'UPDATE ... <query that references column_name> ...;';
END
Run Code Online (Sandbox Code Playgroud)

也是为什么我避免使用速记元数据帮助器(例如OBJECT_NAME()SCHEMA_NAME()等),而是建议创建您自己的帮助器视图