当前位置: 首页 > 面试题库 >

COALESCE-保证短路?

汪兴旺
2023-03-14
问题内容

从这个问题出发,一个关于使用COALESCE简化复杂逻辑树的简洁答案。我考虑了短路问题。

例如,在大多数语言的函数中,对参数进行全面评估,然后将其传递给函数。在C中:

int f(float x, float y) {
    return x;
}

f(a, a / b) ; // This will result in an error if b == 0

这似乎不是COALESCESQL Server中“功能”的限制:

CREATE TABLE Fractions (
    Numerator float
    ,Denominator float
)

INSERT INTO Fractions VALUES (1, 1)
INSERT INTO Fractions VALUES (1, 2)
INSERT INTO Fractions VALUES (1, 3)
INSERT INTO Fractions VALUES (1, 0)
INSERT INTO Fractions VALUES (2, 0)
INSERT INTO Fractions VALUES (3, 0)

SELECT Numerator
    ,Denominator
    ,COALESCE(
        CASE WHEN Denominator = 0 THEN 0 ELSE NULL END,
        CASE WHEN Numerator <> 0 THEN Numerator / Denominator ELSE NULL END,
        0
    ) AS TestCalc
FROM Fractions

DROP TABLE Fractions

如果它正在评估分母= 0的第二种情况,那么我会期望看到类似以下的错误:

Msg 8134, Level 16, State 1, Line 1
Divide by zero error encountered.

我发现了一些提到
相关的甲骨文。并使用SQL
Server
进行了一些测试。当您包含用户定义的函数时,短路可能会中断。

那么,这种行为是否应该由ANSI标准来保证?


问题答案:

我只是看了链接的文章,并且可以确认短路对于COALESCE和ISNULL都可能失败。

如果涉及到任何子查询,它似乎会失败,但是它对于标量函数和硬编码值可以正常工作。

例如,

DECLARE @test INT
SET @test = 1
PRINT 'test2'
SET @test = COALESCE(@test, (SELECT COUNT(*) FROM sysobjects))
SELECT 'test2', @test
-- OUCH, a scan through sysobjects

COALESCE是根据ANSI标准实施的。它只是CASE语句的简写形式。ISNULL不是ANSI标准的一部分。6.9节似乎并没有明确要求短路,但它确实暗示when应返回语句中的第一个true子句。

这是一些适用于基于标量的函数的证明(我在SQL Server
2005
上运行了它):

CREATE FUNCTION dbo.evil
(
)
RETURNS int
AS
BEGIN
    -- Create an huge delay
    declare @c int
    select @c = count(*) from sysobjects a
    join sysobjects b on 1=1
    join sysobjects c on 1=1
    join sysobjects d on 1=1
    join sysobjects e on 1=1
    join sysobjects f on 1=1
    return @c / 0
END
go

select dbo.evil()
-- takes forever

select ISNULL(1,  dbo.evil())
-- very fast

select COALESCE(1,  dbo.evil())
-- very fast

这证明CASE的基础实现将执行子查询。

DECLARE @test INT
SET @test = 1
select
    case
        when @test is not null then @test
        when @test = 2 then (SELECT COUNT(*) FROM sysobjects)
        when 1=0 then (SELECT COUNT(*) FROM sysobjects)
        else (SELECT COUNT(*) FROM sysobjects)
    end
-- OUCH, two table scans. If 1=0, it does not result in a table scan.


 类似资料:
  • 我得到的一个区别是,使用可以增加/减少分区的数量,而使用只能减少分区的数量。 如果分区分布在多台机器上,并且运行,它如何避免数据移动?

  • 我试图理解RabbitMQ对发布的保证——到目前为止没有成功——我想知道是否有人可以帮助我解决这个问题: 绑定 交易所 A - 交易所 A - 交易所B- 交易所C- 属性 B1和C1被声明为持久队列 B1和C1都是镜像队列 所有交换机均声明为扇出 我正在运行一个具有多个节点的RabbitMQ集群,因此队列可以在不同的节点上主控 如果我发布到Exchange A,那么我是将消息发布到所有队列还是不

  • 我试图将Auth0整合到我的web应用程序用户登录中。但是,我总是得到“无效的验证码格式。”。 我注意到 Auth0Lock 提供的验证码是 ,而直接 GET 返回的验证码要大得多 。 问题是:有了Auth0,我应该如何使用校验码来换取access_token。

  • 问题内容: 如果列匹配,是否有很好的方法在SQL中表示选择特定的行,否则选择更通用的行?就像是: 我只希望它返回一个特定的记录(如果存在),否则,如果找不到特定的列匹配项,则返回通用的“ ALL”记录。看起来COALESCE与我正在寻找的相似,但我不知道在语法上如何工作。 问题答案: @Blorgbeard答案(使用前1个和排序依据)可能是最好的方法,但只是有所不同,您还可以使用子查询,但不存在:

  • 我有一个与 Rest Assured 中的响应正文验证相关的问题。让我们假设,我有一个像json这样的响应体。 我需要检查: 如果图书部分包含儿童类型 如果一本儿童类书籍的自动名称为Eric 第一个断言可以是这样的: 但是我需要检查它的作者的名字是否是威廉。有没有办法使用jsonPath检查它? 我假设,我可以做反序列化(例如,x. List

  • 我已经设置了AWS认知与我自己的用户池,但当我创建一个有效的电话号码的用户,我没有收到验证短信在该手机上。我还创建了角色,允许亚马逊Cognito发送短信。请帮助我调试问题,并让我知道如果需要更多的细节。