基于三张业务表查询每月总消费额排名前三的客户姓名及月度排名
需求说明
统计每个月按总购买金额排序的前3名客户姓名,以及对应客户在当月的消费排名。
涉及表结构
所有表字段已做中文对照:
- 产品表(Product)
产品ID(Product_id) 产品名称(product_name) 产品单价(product_price) P1 ABC 20 P2 DEF 30
- 销售表(Sales)
客户ID(Cust_id) 消费日期(Date) 购买数量(Quantity) 产品ID(Product_id) C1 2021年1月1日 3 P1 C1 2021年2月2日 4 P2 C2 2021年1月5日 6 P1 C2 2021年1月7日 1 P1 C3 2021年2月9日 5 P2
- 客户表(Customer)
客户ID(ID) 客户姓名(Name) C1 JKL C2 MNO C3 OPQ
实现逻辑
- 关联销售表和产品表,计算单条销售记录的消费金额:
购买数量 * 产品单价 - 按统计月份、客户ID分组,汇总每个客户单月的总消费金额
- 关联客户表匹配客户姓名
- 用窗口函数按月份分区,对单月客户总消费金额降序排序得到排名
- 过滤排名≤3的记录即为所需结果
参考SQL代码(支持窗口函数的数据库通用,如MySQL 8.0+、PostgreSQL、Oracle等)
WITH monthly_consumption AS ( -- 统计每个客户每月的总消费金额 SELECT DATE_FORMAT(s.`Date`, '%Y-%m') AS 统计月份, -- 不同数据库日期格式化函数可替换:PostgreSQL用TO_CHAR(s."Date", 'YYYY-MM'),Oracle用TO_CHAR(s."Date", 'YYYY-MM') s.Cust_id AS 客户ID, c.Name AS 客户姓名, SUM(s.Quantity * p.product_price) AS 月总消费金额 FROM Sales s LEFT JOIN Product p ON s.Product_id = p.Product_id LEFT JOIN Customer c ON s.Cust_id = c.ID GROUP BY DATE_FORMAT(s.`Date`, '%Y-%m'), s.Cust_id, c.Name ), monthly_cust_rank AS ( -- 计算每个客户当月消费排名 SELECT 统计月份, 客户姓名, 月总消费金额, DENSE_RANK() OVER (PARTITION BY 统计月份 ORDER BY 月总消费金额 DESC) AS 当月消费排名 FROM monthly_consumption ) -- 过滤取前3名 SELECT 统计月份, 客户姓名, 当月消费排名, 月总消费金额 FROM monthly_cust_rank WHERE 当月消费排名 <= 3 ORDER BY 统计月份, 当月消费排名;
本案例查询结果
| 统计月份 | 客户姓名 | 当月消费排名 | 月总消费金额 |
|---|---|---|---|
| 2021-01 | MNO | 1 | 140 |
| 2021-01 | JKL | 2 | 60 |
| 2021-02 | OPQ | 1 | 150 |
| 2021-02 | JKL | 2 | 120 |
注:本案例中两个月份的消费客户数均不足3人,因此所有客户均进入结果列表。如果使用MySQL 5.x等不支持窗口函数的版本,可改用关联子查询实现排名计算,核心逻辑一致。
内容的提问来源于stack exchange,提问作者user17104304
相关产品推荐
相关产品推荐

