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

多对多关联数据查询:将Service与Service_Payment表的付款方式金额转为同行列并消除重复行

解决Service与Service_Payment关联后的重复行及行转列需求

嘿,这个问题我太熟悉了!你遇到的重复行问题,本质是因为Service和Service_Payment是一对多的关联关系,直接JOIN的话每一条付款记录都会带出一行服务数据,自然就重复了。要实现把多种付款方式的金额放到同一行,我们需要做**行转列(Pivot)**操作,我给你两种通用的解决办法:

方法一:用CASE WHEN + GROUP BY(兼容绝大多数数据库)

这种写法不依赖数据库特定语法,MySQL、PostgreSQL、SQL Server、Oracle都能用:

SELECT
    s.service_id,
    s.service_name,
    s.service_fees,
    -- 处理Cash付款方式的金额,无记录则显示0
    COALESCE(SUM(CASE WHEN sp.service_payment_method = 'Cash' THEN sp.service_payment_amount ELSE 0 END), 0) AS cash_value,
    -- 处理Credit Card付款方式的金额
    COALESCE(SUM(CASE WHEN sp.service_payment_method = 'Credit Card' THEN sp.service_payment_amount ELSE 0 END), 0) AS credit_card_value,
    -- 处理Driver Collection付款方式的金额
    COALESCE(SUM(CASE WHEN sp.service_payment_method = 'Driver Collection' THEN sp.service_payment_amount ELSE 0 END), 0) AS driver_collection_value,
    -- 处理Bank Transfer付款方式的金额(即使没有记录也显示0)
    COALESCE(SUM(CASE WHEN sp.service_payment_method = 'Bank Transfer' THEN sp.service_payment_amount ELSE 0 END), 0) AS bank_transfer_value
FROM Service s
-- 用LEFT JOIN确保所有服务都能被查询到,哪怕没有付款记录
LEFT JOIN Service_Payment sp ON s.service_id = sp.service_id
-- 按服务的唯一标识分组,确保每个服务只返回一行
GROUP BY s.service_id, s.service_name, s.service_fees;

关键逻辑说明:

  • LEFT JOIN:保证即使某个服务没有任何付款记录,也会被包含在结果中
  • CASE WHEN:根据付款方式匹配对应的金额,不匹配则返回0
  • SUM + GROUP BY:聚合同一服务的所有付款记录,把多行合并成单行,彻底解决重复行问题
  • COALESCE:处理聚合后可能出现的NULL值,确保没有对应付款方式时显示0

方法二:用数据库自带的PIVOT函数(适合SQL Server、Oracle等支持的数据库)

如果你的数据库支持PIVOT语法,写法会更简洁:

SELECT
    service_id,
    service_name,
    service_fees,
    -- 把NULL转成0,确保无对应付款方式时显示0
    ISNULL([Cash], 0) AS cash_value,
    ISNULL([Credit Card], 0) AS credit_card_value,
    ISNULL([Driver Collection], 0) AS driver_collection_value,
    ISNULL([Bank Transfer], 0) AS bank_transfer_value
FROM (
    -- 先关联两张表,得到基础数据集
    SELECT
        s.service_id,
        s.service_name,
        s.service_fees,
        sp.service_payment_method,
        sp.service_payment_amount
    FROM Service s
    LEFT JOIN Service_Payment sp ON s.service_id = sp.service_id
) AS SourceTable
-- 执行PIVOT操作,把付款方式转成列,SUM聚合金额
PIVOT (
    SUM(service_payment_amount)
    FOR service_payment_method IN ([Cash], [Credit Card], [Driver Collection], [Bank Transfer])
) AS PivotTable;

关键逻辑说明:

  • 子查询先获取服务和付款的关联数据
  • PIVOT:自动把service_payment_method的不同值转成列,并用SUM聚合对应金额
  • ISNULL:把PIVOT后空的列值转成0,符合需求中的展示要求

总结

重复行的核心原因是一对多关联导致的多行数据,通过聚合函数+分组或者PIVOT行转列操作,就能把同一服务的多个付款记录合并成单行,同时满足你需要的列展示格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 03:47:42