简体   繁体   English

RANK OVER PARTITION BY 在聚合函数上

[英]RANK OVER PARTITION BY on aggregate functions

Here is a set of 3 tables:这是一组 3 个表:

Orders (ORDER_ID, CUSTOMER_ID, ORDER_DATE)订单(ORDER_ID, CUSTOMER_ID, ORDER_DATE)

Order detail (ORDER_ID, PRODUCT_ID, PRICE, UNITS)订单详细信息(ORDER_ID, PRODUCT_ID, PRICE, UNITS)

Customers (CUSTOMER_ID, SIGNUP_DATE, COUNTRY)客户(CUSTOMER_ID, SIGNUP_DATE, COUNTRY)

I need to identify the top 3 months, by revenue, for each country.我需要按收入确定每个国家/地区的前 3 个月。 This is the query that I thought of:这是我想到的查询:

SELECT c.country
    , MONTH(o.order_date) as _Month
    , SUM(od.price * od.units) AS revenue
    , RANK() OVER (PARTITION BY country, _Month ORDER BY revenue) AS Rank  
FROM orders o 
LEFT JOIN customers c ON o.customer_id = c.customer_id  
JOIN order_detail od 
WHERE o.order_id = od.order_id GROUP BY country, Month
HAVING Rank <= 3

Will this query work because I am not sure if SUM(od.price * od.units) as revenue can be used in the RANK() OVER function or not since it's an aggregate function?这个查询是否有效,因为我不确定SUM(od.price * od.units) as revenue可以用于 RANK() OVER 函数,因为它是一个聚合函数?

In databases that support window functions, this would normally be written as:在支持窗口函数的数据库中,这通常写为:

SELECT cm.*
FROM (SELECT c.country, MONTH(o.order_date) as Month, SUM(od.price * od.units) AS revenue,
             RANK() OVER (PARTITION BY country, MONTH(o.order_date) ORDER BY SUM(od.price * od.units) ) AS Rank 
      FROM orders o LEFT JOIN
           customers c
           ON o.customer_id = c.customer_id  JOIN
           order_detail od 
           ON o.order_id = od.order_id
      GROUP BY country, Month
     ) cm
HAVING Rank <= 3;

This is meant to be more Comment than Answer, since I can format a bit prettier down here, but the typical query logical order of operations goes something along the lines of:这意味着更多的评论而不是答案,因为我可以在这里格式化更漂亮,但典型的查询逻辑操作顺序大致如下:

FROM is built first. FROM首先构建。 JOIN s will be applied.将应用JOIN WHERE will cause the above tables to be filtered GROUP BY and aggregates will be applied. WHERE将导致上面的表被过滤GROUP BY并应用aggregates HAVING is applied.应用了HAVING WINDOW FUNCTION s will be calculated.将计算WINDOW FUNCTION s。 These operate outside of the ORDER BY SELECT will be applied.这些在ORDER BY SELECT之外的操作将被应用。 DISTINCT will be applied.将应用DISTINCT ORDER BY will be applied. ORDER BY将被应用。 TOP / LIMIT will be applied. TOP / LIMIT将被应用。

In general, anything that happens in a step will be available to the steps following it (ie a SELECT alias can be used in the ORDER BY but not in the GROUP BY . But in MySQL, the HAVING can use aliases defined in the SELECT . Of course, the optimizer can always decide to do its own thing and may choose a different order, but this is what usually happens in most flavors of SQL.一般来说,在一个步骤中发生的任何事情都可以用于它之后的步骤(即SELECT别名可以在ORDER BY使用,但不能在GROUP BY 。但在 MySQL 中, HAVING可以使用SELECT定义的别名。当然,优化器总是可以决定做自己的事情,也可以选择不同的顺序,但这通常发生在大多数 SQL 风格中。

A couple of references I have are MS SQL related, but, for the most part, still apply to other types:我拥有的一些参考资料与 MS SQL 相关,但在大多数情况下,仍然适用于其他类型:

https://blog.sqlauthority.com/2009/10/10/sql-server-download-logical-query-processing-poster/ https://blog.sqlauthority.com/2009/10/10/sql-server-download-logical-query-processing-poster/

Confused about Itzik Ben-Gan's Logical Query Processing order in his SQL Server 2005 book and SQL Server 2008 book 对 Itzik Ben-Gan 在他的 SQL Server 2005 book 和 SQL Server 2008 book 中的 Logical Query Processing order 感到困惑

https://accessexperts.com/wp-content/uploads/2015/07/Logical-Query-Processing-Poster.pdf https://accessexperts.com/wp-content/uploads/2015/07/Logical-Query-Processing-Poster.pdf

https://www.brentozar.com/archive/2015/07/logical-query-processing/ https://www.brentozar.com/archive/2015/07/logical-query-processing/

I don't think Gordon Linoff's answer is right.我认为 Gordon Linoff 的回答不正确。

(1) You can not directly call the alias in the Rank() function, which has been mentioned by Gordon (1) Rank()函数中不能直接调用别名,Gordon已经提到过
(2) For your use case, you want to rank the months within each country, the rank part should be (2) 对于你的用例,你想对每个国家的月份进行排名,排名部分应该是

RANK() OVER (PARTITION BY country ORDER BY SUM(od.price * od.units) ) AS Rank

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM