在 OVER 子句中使用 ORDER BY
Posted
技术标签:
【中文标题】在 OVER 子句中使用 ORDER BY【英文标题】:Use ORDER BY in OVER clause 【发布时间】:2019-05-06 01:04:02 【问题描述】:我是 T-SQL 和窗口函数的新手。
我不明白为什么以下两个查询会产生相同的结果:
SELECT
empid, ordermonth, val,
SUM(val) OVER (PARTITION BY empid ORDER BY ordermonth
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS runval
FROM
Sales.EmpOrders;
和
SELECT
empid, ordermonth, val,
SUM(val) OVER(PARTITION BY empid ORDER BY ordermonth) AS runval
FROM
Sales.EmpOrders;
输出是一样的:
第二个查询不是应该为每个 empid 产生相同的总值吗?还是ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
是默认的,在over子句中使用order by时是可选的?
【问题讨论】:
这是默认设置(或者可能是RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
,但在这种情况下它们是相同的。
【参考方案1】:
对于运行总和(和类似的),当两行之间的ORDER BY ...
存在平局时,差异是可见的。考虑这个例子,员工在2006-09-01
上有两个订单:
DECLARE @T TABLE (empid INT, ordermonth DATE, val INT);
INSERT INTO @T VALUES
(1, '2006-07-01', 100),
(1, '2006-08-01', 100),
(1, '2006-09-01', 100),
(1, '2006-09-01', 100),
(1, '2006-10-01', 100);
SELECT empid, ordermonth, val,
runval_rows = SUM(val) OVER (PARTITION BY empid ORDER BY ordermonth ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),
runval_auto = SUM(val) OVER (PARTITION BY empid ORDER BY ordermonth)
FROM @t
empid | ordermonth | val | runval_rows | runval_auto
1 | 2006-07-01 | 100 | 100 | 100
1 | 2006-08-01 | 100 | 200 | 200
1 | 2006-09-01 | 100 | 300* | 400*
1 | 2006-09-01 | 100 | 400* | 400*
1 | 2006-10-01 | 100 | 500 | 500
如果未指定行/范围子句,则 SQL Server 默认为:
如果没有指定 ROWS/RANGE 但指定了 ORDER BY,RANGE UNBOUNDED PRECEDING AND CURRENT ROW 用作窗口的默认值 框架。
用最简单的话来说,SQL Server 将 range* 定义为分区内的一组行,这些行在ORDER BY
子句中指定的列中具有相同的值。因此,第二个变体将第 3 和第 4 视为同一范围的一部分,并在计算运行总和时将它们都包括在内。
* 请注意,此定义与“标准”定义不同,答案仅适用于 SQL Server。
【讨论】:
你能看看这篇文章吗? ***.com/questions/56107566/… 您好,您的回答总是简洁明了。你能看看这个问题吗?感谢一百万dba.stackexchange.com/questions/241509/…【参考方案2】:如果您希望每个empid
具有相同的值,则不要使用ORDER BY
:
SELECT empid, ordermonth, val,
SUM(val) OVER (PARTITION BY empid) AS runval
FROM Sales.EmpOrders;
否则,您的两个表达式是相同的——如果排序键是唯一的。默认在documentation中解释:
如果没有指定 ROWS/RANGE 但指定了 ORDER BY,RANGE UNBOUNDED PRECEDING AND CURRENT ROW 用作窗口的默认值 框架。
【讨论】:
以上是关于在 OVER 子句中使用 ORDER BY的主要内容,如果未能解决你的问题,请参考以下文章
优化 sum() over(order by...) 子句抛出“超出资源”错误
无法在 Oracle 的窗口函数中使用 ORDER BY 子句
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) 是不是保留订单?