You need to enable JavaScript to run this app. 如何用SQL从表中按分组提取累计贡献占比前50%的行
优惠活动
大模型
产品
解决方案
定价
更多

如何用SQL从表中按分组提取累计贡献占比前50%的行

最优SQL实现方案

实现逻辑

完全对齐需求的筛选规则:

  • 先按c1分组算出每组所有c3的总和
  • 组内把c3从大到小排序,从上到下逐行累加c3的值
  • 只要某行加入累加队列之前,之前的累加值还没到组总和的50%,这行就必须保留——哪怕加完这行之后累计占比已经超过50%,也要算进去。比如示例里A组单看15的贡献占比才42.8%,没到50%,加上12之后占比到77%,超过了,那这两行都要留。

可直接运行的SQL代码

WITH base_calc AS (
    SELECT
        c1,
        c2,
        c3,
        -- 计算每个c1分组的c3总和
        SUM(c3) OVER (PARTITION BY c1) AS group_total,
        -- 组内按c3降序,逐行累计c3值
        SUM(c3) OVER (
            PARTITION BY c1
            ORDER BY c3 DESC
            ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        ) AS running_total
    FROM 替换为你的实际源表名
)
-- 筛选条件:累加当前行c3之前的累计值,还没达到组总和的50%
SELECT c1, c2, c3
FROM base_calc
WHERE running_total - c3 < group_total * 0.5
ORDER BY c1, c3 DESC;

结果校验(对应用户给出的示例数据)

以A分组为例验证:

  • 组内c3总和 = 15+12+8 = 35,50%阈值为17.5
  1. c3=15的行:累计值为15,减去当前行c3后为0,0<17.5,保留
  2. c3=12的行:累计值为15+12=27,减去当前行c3后为15,15<17.5,保留
  3. c3=8的行:累计值为27+8=35,减去当前行c3后为27,27>17.5,过滤
    最终筛出来的结果和示例期望输出完全一致。

方案特点

  • 性能最优:全流程仅对源表做一次扫描,所有分组统计、累计计算都靠窗口函数在单次扫描中完成,没有自连接、多层嵌套子查询导致的重复扫表开销,千万级以上数据量下的运行效率远高于传统写法
  • 无边界偏差:不管是累计值刚好等于50%、还是组内存在多个相同c3值的场景,筛选结果都不会出错
  • 适配性强:所有支持标准窗口函数的SQL引擎(MySQL 8.0+、PostgreSQL、SQL Server、Hive、Spark SQL、ClickHouse等)都能直接运行,无需额外语法适配

如果碰到不支持窗口函数的老旧环境(比如MySQL 5.x),需要通过同组自连接的方式计算累计值,但这种写法性能较差,仅适合小数据量场景临时使用


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.06 19:24:06