SQL月度统计需求:近3个月promo与deprecator求和差值转百分比
实现思路与SQL代码示例
先明确核心需求:按月份计算promo的总计数减去deprecator的总计数,再转换为占两者总和的百分比,同时只取最近3个月的数据。下面是分步思路和代码实现:
核心步骤拆解
- 锁定近3个月数据:先过滤时间范围,确保只处理目标月份的数据。这里的"近3个月"默认指从当前月份往前推2个月的完整月份(比如当前是10月,取8、9、10月),用日期截断函数统一月份格式。
- 按月份分组聚合:用条件聚合分别计算每个月
promo和deprecator的总计数,避免多次子查询的冗余。 - 计算百分比差值:通过
(promo总和 - deprecator总和) / 两者总和 * 100得到百分比,同时用NULLIF处理总和为0的异常情况(避免除以0报错)。 - 优化结果展示:可选保留小数位数,让结果更直观。
通用SQL代码示例(以PostgreSQL为例)
-- 按月份计算promo与deprecator的差值百分比,取近3个月数据 SELECT DATE_TRUNC('month', date_ref) AS month_ref, -- 截断到月份,作为分组依据 -- 计算当月promo的总计数 SUM(CASE WHEN evaluation_name = 'promo' THEN count_evaluation_name ELSE 0 END) AS total_promo, -- 计算当月deprecator的总计数 SUM(CASE WHEN evaluation_name = 'deprecator' THEN count_evaluation_name ELSE 0 END) AS total_deprecator, -- 计算差值百分比,NULLIF避免除以0 ROUND( (SUM(CASE WHEN evaluation_name = 'promo' THEN count_evaluation_name ELSE 0 END) - SUM(CASE WHEN evaluation_name = 'deprecator' THEN count_evaluation_name ELSE 0 END)) / NULLIF(SUM(count_evaluation_name) FILTER (WHERE evaluation_name IN ('promo', 'deprecator')), 0) * 100, 2 -- 保留2位小数 ) AS difference_percentage FROM your_table_name -- 替换成你的数据表名 WHERE -- 筛选近3个月的完整月份数据 date_ref >= DATE_TRUNC('month', CURRENT_DATE) - INTERVAL '2 months' -- 只处理目标类型,减少计算量 AND evaluation_name IN ('promo', 'deprecator') GROUP BY DATE_TRUNC('month', date_ref) ORDER BY month_ref DESC; -- 按月份倒序,最近的月份在前
不同数据库的适配说明
如果使用其他数据库,需要调整日期处理函数:
- MySQL:将
DATE_TRUNC('month', date_ref)替换为DATE_FORMAT(date_ref, '%Y-%m-01'),CURRENT_DATE换成CURDATE(),INTERVAL '2 months'换成INTERVAL 2 MONTH。 - SQL Server:将
DATE_TRUNC('month', date_ref)替换为DATEFROMPARTS(YEAR(date_ref), MONTH(date_ref), 1),CURRENT_DATE - INTERVAL '2 months'换成DATEADD(MONTH, -2, DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1))。 - Oracle:将
DATE_TRUNC('month', date_ref)替换为TRUNC(date_ref, 'MM'),CURRENT_DATE - INTERVAL '2 months'换成ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -2)。
关键细节提示
- 用
FILTER子句(PostgreSQL支持)或CASE限定只计算promo和deprecator的总和,避免其他evaluation_name的数据干扰结果。 NULLIF函数用来防止某个月份两类数据总计数为0时出现除以0的错误,此时百分比会返回NULL,你可以根据需求用COALESCE替换为0。- 如果"近3个月"指过去90天而非完整月份,可将WHERE条件改为
date_ref >= CURRENT_DATE - INTERVAL '90 days',分组仍按月份处理。
内容的提问来源于stack exchange,提问作者Ara_V
相关产品推荐
相关产品推荐

