为什么COALESCE为单个列返回多个无效列名错误?



当使用COALESCE编写SQL查询时,我注意到在特定情况下,它会为单个无效的列名抛出多个错误。

如果我编写下面的查询并尝试执行它,我会收到一条错误消息告诉我,简而言之,我是一个白痴,这个列不存在。

DECLARE @a TABLE (Column1 INT, Column2 INT)
-- This will return one error, complaining about NeverHeardOfIt
SELECT 
    COALESCE
      (
        Column1, 
        Column2, 
        NeverHeardOfIt
      ) 
FROM @a

Msg 207, Level 16, State 1, Line 8无效的列名"NeverHeardOfIt"。

但是,如果我稍微改变查询,将无效列放在COALESCE语句的前面,我将收到两个错误:

DECLARE @a TABLE (Column1 INT, Column2 INT)
-- This will return two errors, both complaining about NeverHeardOfIt
SELECT 
    COALESCE
      (
        Column1, 
        NeverHeardOfIt, 
        Column2
      ) 
FROM @a 

Msg 207, Level 16, State 1, Line 7无效的列名"NeverHeardOfIt"。

消息207,16级,状态1,第7行无效列名字"NeverHeardOfIt"。

我已经测试了几个不同的场景,似乎只有在合并三个或更多列时才会发生这种情况,并且无效列不是最后一列。显然,"修复"这个问题很容易——不要引用无效的列!但我很想知道为什么,确切地说,COALESCE()函数抛出同样的错误两次。我能想到的最好的情况是,在底层,SQL正在编写多个语句,表示类似以下语句:

如果Column 1为NULL,使用NeverHeardOfIt

如果NeverHeardOfIt为NULL,则使用Column2

如果是这样的话,那么当我执行它时,我可以看到函数如何/为什么会为它在幕后生成的每个"语句"返回一个错误。

有没有人知道这是正确的,或者知道这将返回两个错误的另一个原因?

我认为双错误消息是一个bug,但是是一个非常小的bug。但是,原因是coalesce()(以及choose())实际上是简写。所以:

coalesce(a, b, c)

是:

(case when a is not null then a
      when b is not null then b
      else c
 end)

注意,最后一个元素只出现一次——因此,当缺失的列位于末尾时,您只会得到一次错误。

这可能看起来像一个神秘的细节,但它实际上很重要。例如,如果其中一个值是子查询——子查询的运行成本可能很高——那么它将在coalesce()的求值中运行两次。当性能是一个问题,并且一个或多个值是子查询时,我甚至更喜欢isnull(),它在这些情况下性能更好。通常,我倾向于使用ANSI标准函数。

最新更新