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

如何在SQL查询中按合同起始年度逐年统计应付金额并以列形式展示

解决方案:按合同年度偏移统计应付金额并转列

哈哈,这个需求我上周刚帮同事处理过!本质就是把按合同年度聚合的结果行转列,核心是先搞定每个金额对应的是合同的第几个年度,再用条件聚合把不同年度的总和拆成单独的列。我给你两种常用的实现方式,基本适配所有主流SQL方言~

首先得明确几个前提(如果你的表结构不一样,稍微改改字段名就行):
假设我们有个表叫contract_payments,存了每个合同的年度应付记录,字段包括:

  • contract_id:合同唯一ID
  • start_date:合同起始日期(DATE类型)
  • payment_date:该笔应付对应的日期(用来判断属于合同的第几个年度)
  • due_amount:该年度的应付金额

方法1:通用条件聚合(所有SQL方言都支持)

这是最稳妥的方式,用CASE WHEN配合SUM实现条件聚合,把不同年度的总和映射到单独的列:

SELECT
    -- 合同第1年:付款年份 = 合同起始年份
    SUM(CASE 
        WHEN YEAR(start_date) = YEAR(payment_date)
        THEN due_amount 
        ELSE 0 
    END) AS annual_amount_1,
    -- 合同第2年:付款年份 = 起始年份 + 1
    SUM(CASE 
        WHEN YEAR(start_date) + 1 = YEAR(payment_date)
        THEN due_amount 
        ELSE 0 
    END) AS annual_amount_2,
    -- 合同第3年:付款年份 = 起始年份 + 2
    SUM(CASE 
        WHEN YEAR(start_date) + 2 = YEAR(payment_date)
        THEN due_amount 
        ELSE 0 
    END) AS annual_amount_3
FROM contract_payments
-- 可选:过滤掉期限超过3年的合同
WHERE YEAR(end_date) - YEAR(start_date) <= 2;

关键逻辑解释:

  • 用YEAR()函数提取日期的年份(如果你的SQL方言不支持,比如Oracle用EXTRACT(YEAR FROM date)替代)
  • 通过年份差判断该笔应付属于合同的第几个年度:差为0是第1年,差为1是第2年,以此类推
  • CASE WHEN会把符合条件的due_amount保留,不符合的设为0,再用SUM汇总所有符合条件的金额

方法2:先拆分年度再聚合(适合总金额分摊场景)

如果你的表是存的合同总应付金额(不是年度拆分后的),需要先把总金额平摊到每一年,再统计总和:

SELECT
    SUM(CASE WHEN contract_year_offset = 0 THEN annual_due ELSE 0 END) AS annual_amount_1,
    SUM(CASE WHEN contract_year_offset = 1 THEN annual_due ELSE 0 END) AS annual_amount_2,
    SUM(CASE WHEN contract_year_offset = 2 THEN annual_due ELSE 0 END) AS annual_amount_3
FROM (
    -- 子查询:拆分每个合同的年度分摊金额和年度偏移
    SELECT
        contract_id,
        start_date,
        end_date,
        -- 把总金额平摊到每一年
        due_amount / (YEAR(end_date) - YEAR(start_date) + 1) AS annual_due,
        -- 生成年度偏移(0=第1年,1=第2年...)
        generate_series(0, YEAR(end_date) - YEAR(start_date)) AS contract_year_offset
    FROM contracts
) AS contract_annual_split;

注意事项:

  • generate_series是PostgreSQL的函数,MySQL可以用递归CTE替代生成年度偏移;SQL Server用ROW_NUMBER()配合递归
  • 如果合同是按生效后12个月为一个年度(不是自然年),那不能直接用年份差,得用月份差计算:
    -- 按合同生效后12个月为年度的判断逻辑
    SUM(CASE WHEN FLOOR(DATEDIFF(MONTH, start_date, payment_date)/12) = 0 THEN due_amount ELSE 0 END) AS annual_amount_1
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 09:42:31