如何用SQL统计全年各月在售产品数量?是否需使用循环?
解决全年各月在售产品数量统计问题
原始数据表
| product_id | start_month | end_month |
|---|---|---|
| 1 | 3 | 12 |
| 2 | 1 | 2 |
| 3 | 4 | 6 |
| 4 | 4 | 8 |
| 5 | 5 | 5 |
| 6 | 10 | 11 |
解决方案:无需循环,用月份序列关联统计
你提到的WHERE month >= start_month AND month <= end_month思路是对的,但需要先构造出1-12月的完整月份列表,再和原表做关联统计——完全不需要循环,用循环反而属于过度设计,会增加复杂度且效率更低。
具体实现步骤
生成1-12月的月份序列:不同数据库有不同的生成方式,以下是几种常见写法:
- MySQL:用UNION ALL生成
WITH months AS ( SELECT 1 AS month UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12 ) - PostgreSQL:用generate_series函数
WITH months AS ( SELECT generate_series(1,12) AS month ) - SQL Server:用VALUES子句生成
WITH months AS ( SELECT month FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) AS m(month) )
- MySQL:用UNION ALL生成
关联原表统计各月在售产品数:将月份序列表和产品表关联,筛选出每个月处于在售区间的产品,再分组计数:
WITH months AS ( -- 替换为对应数据库的月份生成语句 SELECT 1 AS month UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12 ) SELECT m.month, COUNT(DISTINCT p.product_id) AS on_sale_count FROM months m LEFT JOIN your_table_name p ON m.month BETWEEN p.start_month AND p.end_month GROUP BY m.month ORDER BY m.month;
结果说明
执行上述SQL后,会得到1-12月每个月的在售产品数量,例如:
- 1月:1个(product_id=2)
- 4月:3个(product_id=1、3、4)
- 5月:4个(product_id=1、3、4、5)
关于循环的问题
完全不需要用循环实现这个需求。循环属于SQL中的过程化写法,不仅代码冗余,而且对于这种集合式的统计需求,关联查询的方式效率更高、更符合SQL的设计思想,用循环确实属于过度设计。
内容的提问来源于stack exchange,提问作者Phil Nguyen
相关产品推荐
相关产品推荐

