为啥在窗口函数中使用 GROUP BY

Posted

技术标签:

【中文标题】为啥在窗口函数中使用 GROUP BY【英文标题】:Why use GROUP BY in WINDOW FUNCTION为什么在窗口函数中使用 GROUP BY 【发布时间】:2021-03-19 22:32:24 【问题描述】:

我目前正在使用 Northwind 数据库,希望看到 1997 年有更多订单的公司。我被要求使用 Windows 功能,所以我写了这个

select c.customerid,
       c.companyname,
       rank() over (order by count(orderid) desc )
from customers c
inner join orders o on c.customerid = o.customerid
where date_part('year',orderdate) = 1997;

但是,此代码要求我将 GROUP BY 与 c.customerid 一起使用。我根本不明白为什么。假设这段代码会给我所有的客户 id 和名称,然后窗口函数会根据订单数量给他们一个排名。那么为什么要对它们进行分组呢?

【问题讨论】:

【参考方案1】:

这里:

rank() over (order by count(orderid) desc )

您在窗口函数 (count(orderid)) 的 over() 子句中有一个聚合函数,因此您确实需要一个 group by 子句。您的想法是将同一客户的所有订单放在同一组中:

select c.customerid,
       c.companyname,
       rank() over (order by count(*) desc) as rn
from customers c
inner join orders o on c.customerid = o.customerid
where o.orderdate = date '1997-01-01' and o.orderdate < '1998-01-01'
group by c.customerid;

注意事项:

过滤文字日期比在日期列上应用日期函数更有效

count(orderid) 在此查询的上下文中等同于 count(*)

Postgres 理解函数依赖列:假设customeridcustomer 的主键,只需将该列放在group by 子句中就足够了

select 子句中为表达式赋予别名是一种很好的做法

另一个好的做法是在所有列前面加上它们所属的表(别名)

【讨论】:

谢谢队友。我现在明白为什么 group by 需要在这里。也感谢您的提示!【参考方案2】:

您可以在 聚合 查询中正确使用它。那将是:

select c.customerid, c.companyname, count(*) as num_orders,
      rank() over (order by count(*) desc) as ranking
from customers c inner join 
     orders o
     on c.customerid = o.customerid
where date_part('year',orderdate) = 1997
group by c.customerid, c.companyname;

这会计算 1997 年每位客户的订单数量。然后根据订单数量对客户进行排名。

我建议你使用:

where orderdate >= '1997-01-01' and
      orderdate < '1998-01-01'

用于按年份过滤。这允许 Postgres 使用可用的索引。

【讨论】:

以上是关于为啥在窗口函数中使用 GROUP BY的主要内容,如果未能解决你的问题,请参考以下文章

在窗口函数中使用不在 Group By 中的列,我得到: SQL 编译错误:[COLUMN_A] is not a valid group by expression

Group BY 查询使用索引,但窗口函数查询不使用

SQL (Hive):在使用 GROUP BY 进行聚合时使用窗口函数

SQL Group By和窗口函数

PostgreSQL中group by中的窗口函数

Django ORM group by,并找到每个组的最新项目(窗口函数)