MySQL 5.5单表查询如何按客户分组获取最新2条符合条件订单
解决方案
你需要通过窗口函数给同个客户的订单按时间排序打标,再筛选排名前2的记录即可,以下是可直接使用的实现:
通用写法(支持MySQL 8.0+、PostgreSQL、SQL Server等主流数据库)
SELECT CustomerId, Id FROM ( SELECT CustomerId, Id, ROW_NUMBER() OVER ( PARTITION BY CustomerId ORDER BY DateOfOrder DESC, Id DESC ) AS row_rank FROM `order` WHERE `Order` = 'Merchandise' AND DateOfOrder >= '2018-01-01' ) AS ranked_orders WHERE row_rank <= 2;
写法说明
- 核心用
ROW_NUMBER()窗口函数,PARTITION BY CustomerId实现按客户维度分组,组内按DateOfOrder倒序、同日期按主键Id倒序(避免同天订单排序混乱)生成排名序号 - 把原SQL中
year(o.DateOfOrder)>= 2018调整为DateOfOrder >= '2018-01-01',避免对字段做函数运算导致无法命中DateOfOrder字段的索引,大幅提升大表查询性能 - 由于
order是SQL保留关键字,作为表名、字段名使用时需要根据数据库类型做转义:MySQL用反引号包裹,PostgreSQL用双引号包裹,SQL Server用方括号包裹,避免语法报错
兼容写法(适用于不支持窗口函数的MySQL 5.x等老版本数据库)
如果你的数据库版本不支持窗口函数,可以用关联子查询实现相同逻辑:
SELECT o1.CustomerId, o1.Id FROM `order` o1 WHERE o1.`Order` = 'Merchandise' AND o1.DateOfOrder >= '2018-01-01' AND ( SELECT COUNT(*) FROM `order` o2 WHERE o2.CustomerId = o1.CustomerId AND o2.`Order` = 'Merchandise' AND o2.DateOfOrder >= '2018-01-01' AND ( o2.DateOfOrder > o1.DateOfOrder OR (o2.DateOfOrder = o1.DateOfOrder AND o2.Id > o1.Id) ) ) < 2 ORDER BY o1.CustomerId, o1.DateOfOrder DESC;
写法说明
该逻辑通过子查询统计同客户下比当前订单更新的符合条件的订单数,数量小于2即代表当前订单属于该客户最新的2条订单。该写法在数据量较大时性能弱于窗口函数写法,优先选择窗口函数版本。
内容的提问来源于stack exchange,提问作者Harald Bacik
相关产品推荐
相关产品推荐

