SQL嵌套语句问题:书籍上月与本月销售额对比计算
解决按书籍ID统计上月/本月销售额对比的SQL方案
嘿,我来帮你搞定这个SQL嵌套查询的问题!看起来你已经有了初步思路,只是语句没写完,我来给你补全并解释清楚~
首先明确你的核心需求:从book_download_log表中,按Book ID分组,计算每个书籍本月总销售额和上月总销售额,并算出两者的差异百分比。
先处理日期格式的小提醒
你的示例数据里Timestamp是类似5月1日的中文格式,如果数据库里存的是这种字符串,得先转换成标准日期类型才能正确筛选月份。比如MySQL中可以用STR_TO_DATE(Timestamp, '%m月%d日')转换,PostgreSQL可以用TO_DATE(Timestamp, 'FMMonthDD')(注意语言设置适配中文月份)。
完整SQL查询语句(MySQL版本)
SELECT b.book_id, -- 计算差异百分比,用COALESCE处理NULL/0的情况,避免报错 CONCAT(FORMAT(((COALESCE(this_month, 0)/COALESCE(last_month, 1))*100)-100, 2),'%') AS Diff, COALESCE(this_month, 0) AS this_month, COALESCE(last_month, 0) AS last_month FROM -- 先获取所有存在的书籍ID,避免漏掉只有单月数据的书籍 (SELECT DISTINCT book_id FROM book_download_log) b -- 左连接本月销售额统计 LEFT JOIN (SELECT book_id, SUM(Price) AS this_month FROM book_download_log WHERE -- 筛选本月数据,注意转换日期格式 YEAR(STR_TO_DATE(Timestamp, '%m月%d日')) = YEAR(CURRENT_DATE) AND MONTH(STR_TO_DATE(Timestamp, '%m月%d日')) = MONTH(CURRENT_DATE) GROUP BY book_id) tm ON b.book_id = tm.book_id -- 左连接上月销售额统计 LEFT JOIN (SELECT book_id, SUM(Price) AS last_month FROM book_download_log WHERE -- 筛选上月数据 YEAR(STR_TO_DATE(Timestamp, '%m月%d日')) = YEAR(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)) AND MONTH(STR_TO_DATE(Timestamp, '%m月%d日')) = MONTH(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)) GROUP BY book_id) lm ON b.book_id = lm.book_id;
关键部分解释
- 获取所有书籍ID:用
(SELECT DISTINCT book_id FROM book_download_log)确保不管书籍在上月还是本月有销售,都能出现在结果里,不会因为某一月没数据被过滤掉。 - 子查询统计销售额:两个子查询分别计算本月和上月的总销售额,按
book_id分组聚合。 - 处理NULL/0值:用
COALESCE把NULL转换成0,避免计算时出现错误;如果上月销售额为0,用COALESCE(last_month, 1)代替,防止除以0的报错(你可以根据实际需求调整,比如上月没销售时显示“N/A”)。 - 日期筛选:通过
YEAR()和MONTH()函数匹配当前月和上月的数据,如果你的Timestamp是标准时间戳(比如2024-05-01),可以直接用Timestamp代替STR_TO_DATE(Timestamp, '%m月%d日')。
PostgreSQL版本参考
如果用PostgreSQL,日期处理可以用DATE_TRUNC更简洁:
SELECT b.book_id, CONCAT(TO_CHAR(((COALESCE(this_month, 0)/NULLIF(last_month, 0))*100)-100, 'FM9999.99'),'%') AS Diff, COALESCE(this_month, 0) AS this_month, COALESCE(last_month, 0) AS last_month FROM (SELECT DISTINCT book_id FROM book_download_log) b LEFT JOIN (SELECT book_id, SUM(Price) AS this_month FROM book_download_log WHERE DATE_TRUNC('month', "Timestamp") = DATE_TRUNC('month', CURRENT_DATE) GROUP BY book_id) tm ON b.book_id = tm.book_id LEFT JOIN (SELECT book_id, SUM(Price) AS last_month FROM book_download_log WHERE DATE_TRUNC('month', "Timestamp") = DATE_TRUNC('month', CURRENT_DATE - INTERVAL '1 month') GROUP BY book_id) lm ON b.book_id = lm.book_id;
测试你的示例数据
假设你的示例数据是:
| Timestamp | Book ID | Price |
|---|---|---|
| 5月1日 | 10 | 100 |
| 5月2日 | 20 | 200 |
| 5月3日 | 30 | 300 |
如果当前是5月,上月(4月)没有数据,结果会是:
| book_id | Diff | this_month | last_month |
|---|---|---|---|
| 10 | 10000.00% | 100 | 0 |
| 20 | 10000.00% | 200 | 0 |
| 30 | 10000.00% | 300 | 0 |
如果4月有对应书籍的销售数据,就会正常计算差异啦~
内容的提问来源于stack exchange,提问作者Osoba Osaze
相关产品推荐
相关产品推荐

