sql-server - ORDER BY 中的字段影响窗口函数的结果
问题描述
我有一个简单的 T-SQL 查询,它计算所有记录的行数、行数和总容量:
DECLARE @t TABLE
(
id varchar(100),
volume float,
prev_date date
);
INSERT INTO @t VALUES
('0318610084', 100, '2019-05-16'),
('0318610084', 200, '2016-06-04');
SELECT
row_num = ROW_NUMBER() OVER (PARTITION BY id ORDER BY prev_date),
rows_count = COUNT(*) OVER (PARTITION BY id ORDER BY prev_date),
vol_total = SUM(volume) OVER (PARTITION BY id ORDER BY prev_date),
*
FROM @t;
我得到以下结果:
但是,这不是我所期望的:在所有两行中,rows_count必须为 2,vol_total必须为 300:
解决方法是添加ROWS BETWEEN UNBOUNDED PRECEDING 和 UNBOUNDED FOLLOWING。但是,我认为必须有另一种方法。
最后我发现 ORDER BY 子句必须使用id字段而不是prev_date字段:
row_num = ROW_NUMBER() OVER (PARTITION BY id ORDER BY id),
rows_count = COUNT(*) OVER (PARTITION BY id ORDER BY id),
vol_total = SUM(volume) OVER (PARTITION BY id ORDER BY id)
在此更改之后,查询的输出与预期的一样。但!我不明白为什么会这样?排序如何影响分区?
解决方案
对于聚合函数,通常不需要在窗口定义中具有顺序,除非您想以有序的方式一次进行聚合,这就像运行总计。只需删除订单即可解决问题。
如果我想用另一种方式来解释它,它就像一个窗口,当你移动到另一行时,它会逐行扩展。它从第一行开始,计算从之前的所有行(第一行中只是当前行!)到行位置的聚合。
如果删除顺序,则会为窗口定义中的所有行计算聚合,并且应用窗口的顺序不会生效。
您可以更改窗口定义中的顺序以查看其效果。
当然,排名函数需要顺序,这一点仅适用于聚合。
DECLARE @t TABLE
(
id varchar(100),
volume float,
prev_date date
);
INSERT INTO @t VALUES
('0318610084', 100, '2019-05-16'),
('0318610084', 200, '2016-06-04');
SELECT
row_num = ROW_NUMBER() OVER (PARTITION BY id ORDER BY prev_date),
rows_count = COUNT(*) OVER (PARTITION BY id),
vol_total = SUM(volume) OVER (PARTITION BY id),
*
FROM @t;
在 SqlServer 2012 之后添加的聚合窗口中启用顺序,它不是 2005 年该功能的第一个版本的一部分。
有关聚合窗口函数中顺序的详细说明,这是一个很大的帮助: 生成移动平均和累积总计 - SqlServer 文档
推荐阅读
- docker - 如何将更新的 docker 镜像加载到其他机器上
- swift - 调度队列 - 嵌套、优化和控制
- javascript - 当用户单击VueJS中的按钮时如何动态创建元素并将其附加到dom
- cuda - 线程是否可以自动更新共享内存的 4 个不同位置?
- r - 我在使用包 openxlsx 从 R 将图像粘贴到 Excel 中时遇到错误
- c# - 如何通知对象实例之外的属性?
- firebase - 如何在没有错误的情况下将 Nativescript 安装到 Sidekick NativeScript 应用程序?
- gradle - 为什么在 Gradle 中尝试使用自定义 Kotlin 编译器插件时会出现 UnknownPluginException?
- java - 为接口方法 Java 实现子类型
- jquery - 点击jquery多选选项,所有选项都消失了