You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

关键部分解释

  1. 获取所有书籍ID:用(SELECT DISTINCT book_id FROM book_download_log)确保不管书籍在上月还是本月有销售,都能出现在结果里,不会因为某一月没数据被过滤掉。
  2. 子查询统计销售额:两个子查询分别计算本月和上月的总销售额,按book_id分组聚合。
  3. 处理NULL/0值:用COALESCE把NULL转换成0,避免计算时出现错误;如果上月销售额为0,用COALESCE(last_month, 1)代替,防止除以0的报错(你可以根据实际需求调整,比如上月没销售时显示“N/A”)。
  4. 日期筛选:通过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;

测试你的示例数据

假设你的示例数据是:

TimestampBook IDPrice
5月1日10100
5月2日20200
5月3日30300

如果当前是5月,上月(4月)没有数据,结果会是:

book_idDiffthis_monthlast_month
1010000.00%1000
2010000.00%2000
3010000.00%3000

如果4月有对应书籍的销售数据,就会正常计算差异啦~

内容的提问来源于stack exchange,提问作者Osoba Osaze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:17:59