【问题标题】:Order by column having duplicates for aggregation按具有重复聚合的列排序
【发布时间】:2021-02-05 06:55:49
【问题描述】:
Employees Table
select name, gender, salary, sum(salary) over(order by salary)
from Employees
问题:
为什么按具有重复项的列排序会产生最终值而不是中间值?
例如执行此查询时,3 名员工的薪水 = 5000,最终值,即应该为第 3 名员工生成的值是为第 1 名生成的?
【问题讨论】:
标签:
sql
sql-server
sum
sql-order-by
window-functions
【解决方案1】:
SQL 窗口函数有一个窗口框架子句,用于指定窗口函数中包含哪些行。默认情况下,默认使用range between unbounded preceding and current row,所以你的代码真的是:
sum(salary) over (order by salary range between unbounded preceding and current row)
range 分区平等对待领带,因此所有领带都包含在框架中——或者不包含任何领带。
另一种方法是row 分区,它单独处理每一行:
sum(salary) over (order by salary row between unbounded preceding and current row)
SQL 标准指定range 是默认值(我猜结果是稳定的,见下文)。因此,这是所有数据库中的默认设置。
当工资不同时,它们返回相同的值。但是,它们并不总是与this fiddle 节目相同。
请注意,当存在平局且窗口框架使用rows 时,结果不稳定。这意味着在不同的运行中,您可以在给定的行上得到不同的结果(我可以从个人经验中推断出这非常非常难以调试)。
您可以通过在order by 中包含唯一键来解决此问题,这是 GMB 建议的解决方案。
【解决方案2】:
这就是聚合窗口函数的工作原理。当有关系时,它们都得到相同的值。 count()、min()、max() 等也是如此。
如果您想在每一行上使用不同的值,请在order by 子句中添加另一列(或一组列)以使其具有确定性(即打破平局)。说employee_id是表中的主键,那么:
select name, gender, salary, sum(salary) over(order by salary, employee_id)
from Employees
order by salary, employee_id