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

MySQL分组查询:求和count列并取最小expiry_date及对应id

解决MySQL分组统计并获取最小expiry_date对应id的问题

你的原查询之所以不符合预期,核心问题在于**GROUP BY package_id后,select列表里的mt.id和mt.expiry_date没有使用聚合函数**。在MySQL的非严格SQL模式下,这两个字段会返回分组内任意一行的值,而不是你想要的对应最小expiry_date的id和最小日期本身。另外你加的LEFT JOIN逻辑也没有起到筛选最小日期的作用。

结合你的需求——按package_id分组,统计count总和,同时获取该分组的最小expiry_date(或null)以及对应这个日期的id,我给你两种可行的解决方案:

方案一:使用窗口函数(MySQL 8.0及以上版本推荐)

窗口函数可以在不分组的前提下计算分组统计值,同时给每个分组内的行排序,方便我们筛选出对应最小日期的行:

WITH package_stats AS (
    SELECT
        id,
        package_id,
        count,
        expiry_date,
        -- 计算当前package_id下的count总和
        SUM(count) OVER (PARTITION BY package_id) AS total_count,
        -- 给每个package_id下的行排序:先排非null的日期,再按日期升序,最小日期的行rn=1
        ROW_NUMBER() OVER (
            PARTITION BY package_id
            ORDER BY 
                CASE WHEN expiry_date IS NULL THEN 1 ELSE 0 END, 
                expiry_date ASC
        ) AS row_rank
    FROM my_table
)
SELECT
    id,
    package_id,
    total_count,
    expiry_date
FROM package_stats
WHERE row_rank = 1;

这个查询的逻辑是:

  1. 用SUM(count) OVER (PARTITION BY package_id)计算每个分组的总count,不用提前分组
  2. 用ROW_NUMBER()给每个分组内的行排序:把null日期排到最后,非null日期按升序排列,这样每个分组里row_rank=1的就是你要的最小expiry_date(或null)的行
  3. 最后筛选出每个分组的第一行,得到正确的id、总count和最小日期

方案二:子查询+关联(兼容MySQL 5.x版本)

如果你的MySQL版本不支持窗口函数,可以用子查询先算出每个分组的总count和最小日期,再关联原表找到对应id:

SELECT
    -- 找到对应最小expiry_date的id(如果有多个行日期相同,LIMIT 1取第一个)
    (SELECT id 
     FROM my_table 
     WHERE package_id = agg.package_id 
       AND (expiry_date = agg.min_expiry OR (agg.min_expiry IS NULL AND expiry_date IS NULL))
     LIMIT 1) AS id,
    agg.package_id,
    agg.total_count,
    agg.min_expiry AS expiry_date
FROM (
    -- 先按package_id分组,计算总count和最小expiry_date
    SELECT
        package_id,
        SUM(count) AS total_count,
        MIN(expiry_date) AS min_expiry
    FROM my_table
    GROUP BY package_id
) AS agg;

这个方案的逻辑是:

  1. 内层子查询agg先完成分组统计,得到每个package_id的总count和最小expiry_date
  2. 外层查询通过关联,找到每个package_id下对应最小日期(或null)的id
  3. 如果同一分组内有多个行的expiry_date都是最小值,LIMIT 1会返回其中第一个id,你可以根据需求调整排序规则

这样就能得到你想要的结果:第一行id为2,expiry_date为2010-01-01 00:00:00,同时count总和正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 13:27:55