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

如何查询各公司vat与witholding_tax两类付款的当年最新记录

问题描述

我有两张数据表:

  • Companies(公司表)
  • company_payments(公司付款记录表)

每家公司会产生vat和witholding_tax两类付款,我当前使用的如下SQL只能返回每家公司本年度的最新一条付款记录:

SELECT * FROM companies c 
JOIN ( SELECT MAX(id) max_id, company_id FROM company_payments ) 
c_max ON (c_max.company_id = c.id)
JOIN company_payments cp ON (cp.id = c_max.max_id)
WHERE 
YEAR(cp.last_payment) = YEAR(CURDATE())

现在需要调整查询逻辑,针对每家公司分别返回vat和witholding_tax两类付款的本年度最新记录,若某类付款无对应记录则返回空记录,请问该如何实现该需求?

实现方案

方案1:窗口函数实现(适用于MySQL 8.0+、PostgreSQL等支持窗口函数的数据库)

思路是先生成「所有公司+两类付款类型」的基础行,保证无付款记录的分类也会留空返回,再通过窗口函数分组取最新记录:

WITH type_list AS (
    -- 固定要查询的两类付款类型
    SELECT 'vat' AS payment_type
    UNION ALL
    SELECT 'witholding_tax' AS payment_type
),
ranked_payments AS (
    SELECT
        c.id AS company_id,
        c.*, -- 可替换为你需要的公司表具体字段
        tl.payment_type,
        cp.*, -- 可替换为你需要的付款表具体字段
        -- 按公司+付款类型分组,最新记录排第一,业务上如果按付款时间判断最新,可改为ORDER BY cp.last_payment DESC
        ROW_NUMBER() OVER (PARTITION BY c.id, tl.payment_type ORDER BY cp.id DESC) AS rn
    FROM companies c
    -- 交叉关联付款类型,生成每家公司对应两类付款的基础行
    CROSS JOIN type_list tl
    -- 左关联本年度对应类型的付款记录,无匹配则付款字段为空
    LEFT JOIN company_payments cp 
        ON cp.company_id = c.id
        AND cp.payment_type = tl.payment_type
        AND YEAR(cp.last_payment) = YEAR(CURDATE())
)
-- 取每个分组的最新一条记录
SELECT * FROM ranked_payments WHERE rn = 1;

方案2:兼容低版本MySQL(5.x及以下不支持窗口函数场景)

用关联子查询先拿到每个公司+付款类型的最新记录ID,再关联查询:

SELECT
    c.id AS company_id,
    c.*,
    tl.payment_type,
    cp.*
FROM companies c
CROSS JOIN (
    SELECT 'vat' AS payment_type
    UNION ALL
    SELECT 'witholding_tax' AS payment_type
) tl
-- 先聚合拿到本年每个公司+付款类型的最新付款ID
LEFT JOIN (
    SELECT MAX(id) AS max_id, company_id, payment_type
    FROM company_payments
    WHERE YEAR(last_payment) = YEAR(CURDATE())
    GROUP BY company_id, payment_type
) c_max ON c_max.company_id = c.id AND c_max.payment_type = tl.payment_type
-- 关联拿到完整付款记录
LEFT JOIN company_payments cp ON cp.id = c_max.max_id;

注意:如果你的付款类型字段名不是payment_type,请替换为表中实际对应的字段名即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 07:06:11