这是一组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
,因为它是一个聚合函数?
答案 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 BY
和aggregates
。
HAVING
已应用。
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/
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