IF条款的SQL评估

时间:2012-05-22 14:11:30

标签: sql sql-server-2008

道歉,如果这不合适,但实际上这是'为什么'而不是'如何'。不确定是否合适,但不知道一个更好的地方问我想不出如何用谷歌来表达我想要的东西。

    IF 'hell' = 'freezing over'
    BEGIN
    SELECT log(0)
    END

看看那句话。没有一个世界,其中IF条款将是真实的。如果我尝试运行它,我希望SQL跳过IF子句并移到最后。相反,我得到:

An invalid floating point operation occurred.

这很奇怪。所以我猜这只是SQL做事的方式。除了...

    IF 'hell' = 'freezing over'
    BEGIN
    SELECT 1/0
    END

这里没有错误。 IF子句中的语句仍应生成错误。谁能解释为什么这不会发生?

这是在调试大量SQL计算时出现的,其中EXP(SUM(LOG()))用于在if子句中累积数据。我可以改变代码来阻止再次发生这种情况,但为什么它会在一个未满足的IF子句中进行评估。

干杯。

编辑:额外娱乐。试着抓? Pffft

    IF 1=2
    BEGIN
        BEGIN TRY
            SELECT SQRT(-1)
        END TRY
        BEGIN CATCH
        END CATCH
    END

非数学:

    IF 1=2
    BEGIN
    SELECT SUBSTRING('hello',-1,-1)
    END

4 个答案:

答案 0 :(得分:7)

我的猜测是log(0)由于constant-folding而过早地被有效评估,而1/0不是由于其基数估计或更可能是因为ANSI_WARNINGS设置会影响除以零的期望结果(溢出与空值)。

答案 1 :(得分:2)

解析器根本不具备遵循IF逻辑的智能。请考虑以下示例:

IF (1 = 0)
BEGIN
   CREATE TABLE #t(x INT):
END
ELSE
BEGIN 
   CREATE TABLE #t(x INT):
END

无论您是执行它还是只是解析它,解析器都会查看批处理中的所有CREATE TABLE语句,并确定您尝试创建表两次(第一个副本显然不必存在)为此发生)。结果:

  

Msg 2714,Level 16,State 1,Line 7
已经有一个名为的对象   数据库中的'#t'。

我真的不知道我是否有更好的答案,而不是解析器不像你那么聪明。

您可以通过使用动态SQL将问题推迟到运行时来打败解析器,例如

IF 'hell' = 'freezing over'
BEGIN
  EXEC sp_executesql N'SELECT log(0);';
END

但是我不得不怀疑,为一个永远不会成立的条件设置脚手架有什么意义,并发出一个你知道会出错的语句?

答案 2 :(得分:2)

  

如果我尝试运行,我希望SQL跳过IF子句并移到最后。

当您运行批处理时,会发生三件事

  1. 您的SQL已解析

  2. 您的SQL已编译

  3. 您的SQL已执行

  4. 不幸的是,SQL Server中批处理中的编译和执行错误导致相同的“Query Completed with errors”消息。因此,让我们使用一个更容易看到差异的程序

    考虑以下

    Create proc compiletime
    as 
     SELECT log(0)
     SELECT SQRT(-1)
     SELECT SUBSTRING('hello',-1,-1)
     SELECT 1/0
    

    该程序解析得很好。但是除非我们删除第一个thre SELECT,否则无法编译它,因为我们有一些作为参数无效的常量。如果SELECT 1/0也导致编译时错误而不是运行时错误会很好,但是@Alex K指出行为是基于ANSI_WARNINGS所以它不是编译时错误。

    这就是为什么我们看到前两者之间存在差异的原因。它还解释了为什么TRY CATCH因编译时错误而无效。

    现在为什么SQL Server编译无法访问的代码。因为一般以便知道它无法访问需要解决停止问题。你可以在某些情况下解决这个问题但是这个......


    DECLARE @x as integer
    SET @x = SomeFunction()
    If (1 = @x)
       SomeCompiletime error
    

    会有不同的行为,更令人困惑。

    if (1=0)
       SomeCompiletime error
    

答案 3 :(得分:0)

显然,SQL编译器试图在编译时和运行时评估一些表达式。我的猜测是一个分区被认为不是太贵,所以它推迟到运行时间。另一方面,像log()这样复杂的东西很昂贵,而且他们希望在编译时这样做。

这是猜测。这也意味着这种差异是不确定的。您必须弄清楚哪一个在特定脚本中工作或不起作用 - 并且行为可能会在数据库版本之间发生变化。