You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

MySQL实现产品多日期销量转置(Pivot)查询及性能优化方案

解决产品销量行转列(Pivot)及性能优化问题

很高兴看到你最后用SUM函数解决了问题,运行时间从8分钟降到5秒,这提升真的太给力了!我来帮你梳理下问题的根源和正确的实现思路,也给其他遇到类似需求的朋友做个参考~

问题根源分析

你最初用COUNT函数的问题在于:COUNT会统计所有非NULL值的行数,而你的表达式COUNT(IF(DATE(day) = ..., quantity, 0))里,不管条件是否匹配,返回的都是非NULL值(要么是quantity,要么是0),所以最终每个c0/c1/c2得到的都是该产品在三天内的总记录数,而不是销量总和——这就是为什么所有日期的统计结果都相同。

换成SUM就完全正确了:SUM会把符合条件的quantity累加,不符合的加0,正好得到对应日期的销量,无销量时自然显示0。

正确的实现SQL

基础版本(包含三天内有销量的产品)

这个查询会返回所有在最近三天有销量的产品,按总销量降序排序:

SELECT 
    product,
    SUM(IF(DATE(day) = UTC_DATE(), quantity, 0)) AS c0,  -- 当日销量
    SUM(IF(DATE(day) = UTC_DATE() - INTERVAL 1 DAY, quantity, 0)) AS c1,  -- 昨日销量
    SUM(IF(DATE(day) = UTC_DATE() - INTERVAL 2 DAY, quantity, 0)) AS c2,  -- 前日销量
    SUM(quantity) AS total_sales  -- 用于排序的总销量
FROM sales
WHERE DATE(day) BETWEEN UTC_DATE() - INTERVAL 2 DAY AND UTC_DATE()  -- 过滤仅三天的数据,提升性能
GROUP BY product
ORDER BY total_sales DESC;

进阶版本(包含所有产品,即使三天无销量)

如果需要展示所有产品(哪怕最近三天完全没销量),可以先获取所有产品的列表,再通过LEFT JOIN关联销量数据:

WITH all_products AS (
    SELECT DISTINCT product FROM sales
)
SELECT 
    ap.product,
    COALESCE(SUM(IF(DATE(s.day) = UTC_DATE(), s.quantity, 0)), 0) AS c0,
    COALESCE(SUM(IF(DATE(s.day) = UTC_DATE() - INTERVAL 1 DAY, s.quantity, 0)), 0) AS c1,
    COALESCE(SUM(IF(DATE(s.day) = UTC_DATE() - INTERVAL 2 DAY, s.quantity, 0)), 0) AS c2,
    COALESCE(SUM(s.quantity), 0) AS total_sales
FROM all_products ap
LEFT JOIN sales s 
    ON ap.product = s.product 
    AND DATE(s.day) BETWEEN UTC_DATE() - INTERVAL 2 DAY AND UTC_DATE()
GROUP BY ap.product
ORDER BY total_sales DESC;

额外性能优化提示

你已经通过SUM替代COUNT大幅提升了速度,再加上WHERE条件过滤掉非目标日期的数据,能进一步减少数据库需要处理的行数,让查询更快——这也是你现在查询能秒出结果的原因之一。

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

火山引擎 最新活动