正如标题所示,我想选择用GROUP BY分组的每组行中的第一行。
具体来说,如果我有一个如下所示的采购表:
SELECT * FROM purchases;
我的输出:
id |
customer |
total |
1 |
Joe |
5 |
2 |
Sally |
3 |
3 |
Joe |
2 |
4 |
Sally |
1 |
我想查询每个客户的最大购买量(总购买量)。类似于:
SELECT FIRST(id), customer, FIRST(total)
FROM purchases
GROUP BY customer
ORDER BY total DESC;
预期输出:
FIRST(id) |
customer |
FIRST(total) |
1 |
Joe |
5 |
2 |
Sally |
3 |
通过我的测试,公认的OMG Ponies“受任何数据库支持”解决方案的速度很快。
在这里,我提供了一种相同的方法,但更完整、更干净的任何数据库解决方案。考虑联系(假设希望每个客户只获得一行,甚至每个客户最多获得多条记录),将为采购表中的实际匹配行选择其他采购字段(例如purchase_payment_id)。
任何数据库都支持:
select * from purchase
join (
select min(id) as id from purchase
join (
select customer, max(total) as total from purchase
group by customer
) t1 using (customer, total)
group by customer
) t2 using (id)
order by customer
这个查询相当快,特别是当采购表上有一个类似(customer,total)的复合索引时。
备注:
t1、t2是可以根据数据库删除的子查询别名。注意:截至2017年1月本次编辑,MS-SQL和Oracle数据库目前不支持using(…)子句。您必须自己将其扩展到例如t2.id=purchase.id等。USING语法适用于SQLite、MySQL和PostgreSQL。
这是我们如何通过使用windows函数实现的:
create table purchases (id int4, customer varchar(10), total integer);
insert into purchases values (1, 'Joe', 5);
insert into purchases values (2, 'Sally', 3);
insert into purchases values (3, 'Joe', 2);
insert into purchases values (4, 'Sally', 1);
select ID, CUSTOMER, TOTAL from (
select ID, CUSTOMER, TOTAL,
row_number () over (partition by CUSTOMER order by TOTAL desc) RN
from purchases) A where RN = 1;
在支持CTE和窗口功能的数据库上:
WITH summary AS (
SELECT p.id,
p.customer,
p.total,
ROW_NUMBER() OVER(PARTITION BY p.customer
ORDER BY p.total DESC) AS rank
FROM PURCHASES p)
SELECT *
FROM summary
WHERE rank = 1
任何数据库都支持:
但你需要添加逻辑来打破联系:
SELECT MIN(x.id), -- change to MAX if you want the highest
x.customer,
x.total
FROM PURCHASES x
JOIN (SELECT p.customer,
MAX(total) AS max_total
FROM PURCHASES p
GROUP BY p.customer) y ON y.customer = x.customer
AND y.max_total = x.total
GROUP BY x.customer, x.total