在聚合函数上排除分数

时间:2017-12-11 21:16:06

标签: mysql sql

这是一组3个表:

订单 (ORDER_ID, CUSTOMER_ID, ORDER_DATE)

订单明细 (ORDER_ID, PRODUCT_ID, PRICE, UNITS)

客户 (CUSTOMER_ID, SIGNUP_DATE, COUNTRY)

我需要确定每个国家按收入排名前3个月。 这是我想到的查询:

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

此查询是否有效,因为我不确定是否可以在RANK()OVER函数中使用SUM(od.price * od.units) as revenue,因为它是一个聚合函数?

3 个答案:

答案 0 :(得分:2)

在支持窗口函数的数据库中,这通常写为:

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;

答案 1 :(得分:1)

这意味着更多评论而不是答案,因为我可以在这里格式化一些更漂亮,但典型的查询逻辑操作顺序类似于:

首先构建

FROM。   JOIN将被应用。 WHERE将导致上述表格被过滤 将应用GROUP BYaggregatesHAVING已应用。 WINDOW FUNCTION将被计算出来。这些操作在ORDER BY之外操作 SELECT将被应用。 DISTINCT将被应用。 ORDER BY将被应用。 将应用TOP / LIMIT

通常,步骤中发生的任何事情都可用于其后的步骤(即SELECT中的ORDER BY别名可用于GROUP BY但不能用于HAVING。但在MySQL中,SELECT可以使用public class A { protected String property = ""; @BeforeSpec public void init(){ property = "hello"; } } public class B extends A { @Step("...") public void verifyProperty() { assertEquals(property, "hello"); } } 中定义的别名。当然,优化器总是可以决定做自己的事情并且可以选择不同的顺序,但这通常发生在大多数风格中SQL。

我有几个参考资料与MS SQL相关,但是,在大多数情况下,仍然适用于其他类型:

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

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

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

答案 2 :(得分:0)

我认为Gordon Linoff的答案不正确。

(1)您不能在Gordon提到的Rank()函数中直接调用别名。
(2)对于您的用例,您想要对每个国家/地区中的月份进行排名,排名部分应为

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