如何按客户分组获取Top3最常光顾门店?SQL语句问题排查
按客户统计最常光顾的前3家门店SQL修正
需求
按每个客户统计其最常光顾的前3家门店。
原始数据表
| 客户 | 门店 | 金额 |
|---|---|---|
| Peter | ABC | 10 |
| Peter | ABC | 10 |
| Peter | ABC | 10 |
| Peter | ABC | 10 |
| Peter | 7eleven | 5 |
| Peter | 7eleven | 5 |
| Peter | 7eleven | 5 |
| Peter | Addidas | 64 |
| Peter | Addidas | 64 |
| Peter | Nike | 52 |
| Ben | 7eleven | 5 |
| Ben | 7eleven | 7 |
| Ben | 7eleven | 7 |
| Ben | 7eleven | 3 |
| Ben | Nike | 48 |
| Ben | Nike | 48 |
| Ben | Nike | 48 |
| Ben | Puma | 67 |
| Ben | Puma | 67 |
| Ben | Addidas | 55 |
| Ben | ABC | 12 |
| Diana | Puma | 58 |
| Diana | Puma | 58 |
| Diana | Puma | 58 |
| Diana | Puma | 42 |
| Diana | ABC | 12 |
| Diana | ABC | 12 |
| Diana | ABC | 12 |
| Diana | Sony | 230 |
| Diana | Sony | 130 |
| Kate | Zara | 58 |
| Kate | Zara | 58 |
| Kate | Zara | 58 |
| Kate | Zara | 42 |
| Kate | Post | 12 |
| Kate | Post | 12 |
| Kate | Post | 12 |
| Kate | LG | 230 |
| Kate | LG | 130 |
| Kate | ABC | 12 |
期望结果表
| 客户 | 门店 | 门店光顾频次排名 |
|---|---|---|
| Peter | ABC | 1 |
| Peter | 7eleven | 2 |
| Peter | Addidas | 3 |
| Ben | 7eleven | 1 |
| Ben | Nike | 2 |
| Ben | Puma | 3 |
| Diana | Puma | 1 |
| Diana | ABC | 2 |
| Diana | Sony | 3 |
| Kate | Zara | 1 |
| Kate | Post | 2 |
| Kate | LG | 3 |
原SQL问题分析
你写的SQL有两个核心问题:
- 未先对客户+门店聚合统计光顾频次,直接用窗口函数会让每条原始数据生成一个排名,结果完全偏离需求;
- 窗口函数的
PARTITION BY错误包含了store,导致每个客户的每个门店单独分区,排名失去意义。
修正后的SQL
SELECT 客户, 门店, 门店光顾频次排名 FROM ( SELECT 客户, 门店, RANK() OVER (PARTITION BY 客户 ORDER BY 光顾频次 DESC) AS 门店光顾频次排名 FROM ( -- 第一步:统计每个客户每个门店的光顾次数 SELECT 客户, 门店, COUNT(*) AS 光顾频次 FROM my.table GROUP BY 客户, 门店 ) AS 客户门店频次统计 ) AS 带排名的统计结果 WHERE 门店光顾频次排名 <= 3;
逻辑说明
- 最内层子查询:按客户和门店分组,统计每个客户在每家门店的光顾次数;
- 中间层子查询:基于统计结果,按客户分区,按光顾频次降序用
RANK()生成排名; - 最外层查询:筛选排名前3的记录,得到最终结果。
如果需要处理并列排名场景,可根据需求替换RANK():
DENSE_RANK():并列记录占相同排名,后续排名连续(如两个第1,下一个是第2);ROW_NUMBER():即使频次相同,也生成唯一连续排名(需额外排序字段保证结果稳定)。
内容的提问来源于stack exchange,提问作者Daniyar Azimbayev
相关产品推荐
相关产品推荐

