多对多关联数据查询:将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:根据付款方式匹配对应的金额,不匹配则返回0SUM+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
相关产品推荐
相关产品推荐

