Hon*_*ger 9 sql sql-server divide-by-zero window-functions
I came across this answer on Programming Puzzles & Code Golf. In it, the author uses the expression (though the answer has since been edited to use a different solution):
row_number()over(order by 1/0)
Run Code Online (Sandbox Code Playgroud)
I would have expected the 1/0 to result in a divide by zero exception, but it doesn't.
When I asked the author on PPCG, they replied "because 1/0 is not being calculated. where exists(select 1/0) will have the same effect". This leaves me a bit nonplussed, because where exists(select 1) is valid syntax, but row_number()over(order by 1) is not. So why is the expression in the order by not calculated? The result of the expression is an integer, and an integer is not allowed in the order by. How does SQL Server handle the order by in that case? I assume the effect is the same as row_number()over(order by (SELECT NULL)), but if we give an expression, I'd expect that expression to be evaluated.
Coincidentally, if one uses something like:
SELECT ROW_NUMBER() OVER ( ORDER BY A.x )
FROM (
SELECT *
, 1 / 0 x
FROM master..spt_values
) A
Run Code Online (Sandbox Code Playgroud)
Again, no divide by zero error is reported (when the x column is not selected, naturally). So why is this allowed when an integer is not?
不允许使用整数文字,ORDER BY但允许使用表达式返回整数-否则将无法使用例如CASE表达式。
因此,这就是为什么您被禁止OVER (ORDER BY 1)但显然被允许的原因OVER (ORDER BY 1/0)。我认为这不是您要故意编写的功能。如果您的表达式实际上依赖于行中的任何列,则肯定不允许除以零-这会产生错误:
select name,object_id,ROW_NUMBER() OVER (ORDER BY 1/(object_id-3))
from sys.objects
Run Code Online (Sandbox Code Playgroud)
因此,我将其归结为“优化器足够聪明,可以意识到该表达式不依赖于任何行值,因此所有行的值都是相同的,因此我们无需对其进行计算”。用理智的语言,这会产生警告。
让我们尝试更多的例子......
ROW_NUMBER() OVER (ORDER BY 2/1)
Run Code Online (Sandbox Code Playgroud)
窗口函数和 NEXT VALUE FOR 函数不支持整数索引作为 ORDER BY 子句表达式。
问题在于2/1,它在优化过程的早期不断折叠,因此被视为与不允许的情况2相同。ROW_NUMBER() OVER (ORDER BY 2)
ROW_NUMBER() OVER (ORDER BY LOG(1))
Run Code Online (Sandbox Code Playgroud)
窗口函数和 NEXT VALUE FOR 函数不支持常量作为 ORDER BY 子句表达式。
常量折叠再次开始 - 这次结果不是整数索引,但 SQL Server 无论如何都不允许常量。
ROW_NUMBER() OVER (ORDER BY LOG(-1))
Run Code Online (Sandbox Code Playgroud)
这在最新版本的 SQL Server 上可以成功 - 在旧版本(例如 SQL Server 2008)上您将看到An invalid floating point operation occurred.。CASE 这里的上下文中提到了这个具体案例。编译时常量折叠打破了语义CASE,这在更新的版本中得到了修复。
LOG(-1)在这些错误情况(和)中抑制常量折叠1/0足以使其绕过给出上述错误消息的检查。然而,SQL Server 仍然认为该表达式实际上是一个常量,并且可以稍后进行优化(因此您不会获得排序操作来按该表达式的结果对行进行排序)。
在简化阶段,ROW_NUMBER ORDER BY non_folded_const_expression被简化为只是ROW_NUMBER并non_folded_const_expression从树中删除,不再被引用。因此,它在运行时不会引起任何问题,因为它甚至不存在于最终的执行计划中。