【发布时间】:2011-08-27 20:55:40
【问题描述】:
在询问another question 时,我发现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
错误是窗口函数不支持常量作为 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
...大概是出于同样的原因。但是,这段代码并没有报错:
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
这里与第一个代码块的唯一区别是我将case 语句的条件操作数之一移动到变量@asc 中。这现在工作正常。为什么呢? case 语句仍可能评估为 NULL,这是一个常数,因此它不应该工作......但它确实有效。这在某种程度上是一致的,还是 Microsoft 提出的特殊情况行为?
所有这些行为都可以通过this query 来检查。
更新:此限制不仅适用于 OVER 子句(尽管它们确实给出了不同的错误)- 它适用于自 SQL Server 2005 以来的所有 ORDER BY 子句。Here's a query这也显示了常规 SELECT 的 ORDER BY 子句的限制。
【问题讨论】:
-
1=1不也是一个常数吗?它总是评估为TRUE。 -
@Crack 是的,但它在
case语句中是一个常数,所以我不明白为什么会有所不同?这似乎是在说,“如果该语句肯定评估(或不评估)为 NULL,则不允许。如果它可能评估为 NULL,则允许。”这没有意义......为什么允许后者?语法如何更有效? -
您可以按常数排序。使用
ORDER BY (SELECT NULL)或ORDER BY @@SPID -
您是否尝试对导致窗口函数错误的表达式进行实际排序?它们也会在正确的 ORDER BY 中产生错误:'在 ORDER BY 列表中遇到常量表达式,位置 n'。因此,无论它是否在窗口函数中使用,它都能在 ORDER BY 中始终如一地工作和中断。
-
@Andriy - This depends on compatibility mode。一个非常相似的讨论在这里dbaspot.com/sqlserver-programming/…
标签: sql sql-server tsql