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

MySQL单查询实现按规则生成含diff_cum_year列的新表

MySQL单查询实现按规则生成含diff_cum_year列的新表

嘿,我帮你搞定这个MySQL查询需求啦!结合你给的示例数据和规则,我整理出了一个单查询语句,能直接生成符合要求的新表,下面一步步给你拆解说明:

输入示例表

先把你提供的原始数据整理成清晰的表格:

newIDyearIDnewValore
1202011150
1202011160
1202111170
1202111220
1202111240
1202211330
1202211380
2202022220
2202022310
2202122340
2202122410
2202122490
2202122499
2202222510
2202322550

核心规则回顾

先把你定义的diff_cum_year规则拆解得更清晰,方便理解后续查询逻辑:

  • 规则1(最小年份):如果当前年份是该newID的最小年份,值为同年同newID下每个不同ID的newValore最大值之和。
  • 规则2(单一ID且去年存在):同年同newID只有一个ID,且该ID在去年同newID的记录中存在,值为当前年份该ID的newValore最大值减去去年的diff_cum_year值。
  • 规则3(单一ID且去年不存在):同年同newID只有一个ID,且该ID在去年同newID的记录中不存在,值为当前年份该ID的newValore最大值。
  • 规则4(多个ID):同年同newID有多个不同ID,值为同年每个ID的newValore最大值之和减去去年的diff_cum_year值。

实现查询语句

下面就是能直接运行的单查询代码,记得把original_table替换成你的原始表名,result_table替换成你想要生成的新表名:

WITH yearly_agg AS (
    -- 第一步:按newID、year、ID分组,计算每个分组的newValore最大值
    SELECT 
        newID,
        year,
        ID,
        MAX(newValore) AS max_val
    FROM original_table
    GROUP BY newID, year, ID
),
yearly_sum AS (
    -- 第二步:按newID、year分组,统计同年ID数量、最大值之和,以及单一ID(如果存在)
    SELECT 
        newID,
        year,
        COUNT(DISTINCT ID) AS id_count,
        SUM(max_val) AS sum_max_val,
        CASE WHEN COUNT(DISTINCT ID) = 1 THEN MAX(ID) ELSE NULL END AS single_id
    FROM yearly_agg
    GROUP BY newID, year
),
yearly_prev_data AS (
    -- 第三步:关联去年的数据,获取去年的ID集合和前一年的diff_cum_year占位(后续递归赋值)
    SELECT 
        ys.newID,
        ys.year,
        ys.id_count,
        ys.sum_max_val,
        ys.single_id,
        (SELECT GROUP_CONCAT(DISTINCT ID) FROM yearly_agg ya WHERE ya.newID = ys.newID AND ya.year = ys.year - 1) AS prev_ids
    FROM yearly_sum ys
),
final_calc AS (
    -- 第四步:用递归CTE按规则计算diff_cum_year
    WITH RECURSIVE cte AS (
        -- 递归起始点:每个newID的最小年份,应用规则1
        SELECT 
            newID,
            year,
            sum_max_val AS diff_cum_year
        FROM yearly_prev_data
        WHERE year = (SELECT MIN(year) FROM yearly_prev_data ypd WHERE ypd.newID = yearly_prev_data.newID)
        
        UNION ALL
        
        -- 递归处理后续年份,匹配对应规则计算
        SELECT 
            curr.newID,
            curr.year,
            CASE
                -- 规则4:多个ID的情况
                WHEN curr.id_count > 1 THEN curr.sum_max_val - prev.diff_cum_year
                -- 规则2:单一ID且去年存在该ID
                WHEN curr.id_count = 1 AND FIND_IN_SET(curr.single_id, curr.prev_ids) THEN (SELECT max_val FROM yearly_agg ya WHERE ya.newID = curr.newID AND ya.year = curr.year AND ya.ID = curr.single_id) - prev.diff_cum_year
                -- 规则3:单一ID且去年不存在该ID
                WHEN curr.id_count = 1 AND NOT FIND_IN_SET(curr.single_id, curr.prev_ids) THEN (SELECT max_val FROM yearly_agg ya WHERE ya.newID = curr.newID AND ya.year = curr.year AND ya.ID = curr.single_id)
                ELSE 0
            END AS diff_cum_year
        FROM yearly_prev_data curr
        JOIN cte prev ON curr.newID = prev.newID AND curr.year = prev.year + 1
    )
    SELECT newID, year, diff_cum_year FROM cte
)
-- 创建新表存储结果
CREATE TABLE result_table AS
SELECT * FROM final_calc
ORDER BY newID, year;

代码逻辑说明

  1. yearly_agg:先做基础聚合,算出每个newID-year-ID分组的newValore最大值,这是所有计算的基础。
  2. yearly_sum:进一步聚合到newID-year维度,统计同年的ID数量、最大值总和,以及如果只有一个ID就记录该ID。
  3. yearly_prev_data:关联去年的ID集合,方便后续判断当前ID是否在去年出现过。
  4. 递归CTE(final_calc):
    • 起始点是每个newID的最小年份,直接用规则1计算初始值。
    • 后续年份通过和前一年的结果关联,根据ID数量、ID是否存在等条件匹配规则,计算出当前的diff_cum_year。
  5. 最后用CREATE TABLE AS把结果存入新表,自动完成需求。

预期输出表

运行上面的查询后,生成的新表会和你预期的完全一致:

newIDyeardiff_cum_year
1202060
1202150
1202280
2202030
22021109
2202210
2202340

备注:内容来源于stack exchange,提问作者Luca Folin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 08:19:14