来自窗口函数子句的SQL Server的奇怪不一致行为?

Jez*_*Jez 7 sql t-sql sql-server

在提出另一个问题时,我发现SQL Server(在2005年和2008年都发生过)在处理CASE窗口函数子句中的语句时似乎有奇怪的不一致行为.以下代码给出了错误:

declare @t table (SortColumn int)
insert @t values (1), (2), (3)
declare @asc bit
set @asc = 0

select  row_number() over (order by
            case when 1=1 then SortColumn end asc,
            case when 1=0 then SortColumn end desc) RowNumber
,       *
from    @t
Run Code Online (Sandbox Code Playgroud)

错误是窗口函数不支持常量作为ORDER BY子句表达式. 我认为这是因为case语句可以评估为NULL,这是一个常量.正如可能预期的那样,此代码也会出现相同的错误:

declare @t table (SortColumn int)
insert @t values (1), (2), (3)
declare @asc bit
set @asc = 0

select  row_number() over (order by
            NULL asc,
            NULL desc) RowNumber
,       *
from    @t
Run Code Online (Sandbox Code Playgroud)

......可能是出于同样的原因.但是,此代码不会出错:

declare @t table (SortColumn int)
insert @t values (1), (2), (3)
declare @asc bit
set @asc = 0

select  row_number() over (order by
            case when @asc=1 then SortColumn end asc,
            case when @asc=0 then SortColumn end desc) RowNumber
,       *
from    @t
Run Code Online (Sandbox Code Playgroud)

这里与第一个代码块的唯一区别是我将其中一个case语句的条件操作数移动到一个变量中@asc.这现在工作正常.但是为什么呢?这些case陈述仍然可以评估NULL,这是一个常数,因此它不应该起作用......但确实如此.这是一致的,还是微软提出的特殊情况?

通过玩这个查询可以检查所有这些behvaiour .


更新:此限制不只是适用于OVER条款(虽然他们给出一个不同的错误) -它适用于所有ORDER BY的条款,因为SQL Server 2005的 下面是一个查询还显示了常规限制SELECTORDER BY条款.

Mar*_*ith 4

在线书籍指出“排序列可以包含表达式,但当数据库处于 SQL Server (90) 兼容模式时,表达式无法解析为常量”。然而它没有定义“常数”。

通过思考和一些实验,似乎很清楚这意味着可以在编译时成功计算文字常量值的表达式。

/*Works - Constant at run time but SQL Server doesn't do variable sniffing*/
DECLARE @Foo int
SELECT ROW_NUMBER() OVER (ORDER BY @Foo) 
FROM master..spt_values 

/*Works - Constant folding not done for divide by zero*/
SELECT ROW_NUMBER() OVER (ORDER BY $/0) 
FROM master..spt_values 

/*Fails - Windowed functions do not support 
   constants as ORDER BY clause expressions.*/
SELECT ROW_NUMBER() OVER (ORDER BY $/1) 
FROM master..spt_values 
Run Code Online (Sandbox Code Playgroud)