SQL按指定逻辑去重并筛选金额未抵消目标行实现方案
逻辑评估
你想的按ID分区算金额总和、再匹配对应金额行的思路是完全成立的。核心逻辑很准:去重后同ID下能互相抵消的金额加总为0,最后剩下的未抵消金额,刚好就等于整个ID的金额总和,匹配上就能拿到对应的Item值。
不过这个思路可以少做一步关联,不用把算出来的总和再回连去重表,直接在窗口函数计算时保留所有原字段,外层加筛选条件就行,执行效率更高。
注意:这个逻辑仅适用于你当前的场景——每个ID最终仅存在1笔未抵消的记录,且不存在多笔金额加总恰好等于ID总和的组合。如果后续业务出现同ID多笔未抵消的情况(比如ID=3下去重后有10元、5元、-3元三笔,总和为12),这个匹配逻辑就会失效,需要调整抵消判断规则,但就你给出的示例数据和需求来说,当前逻辑完全够用。
实现代码
优化版(无二次关联,性能更好)
WITH deduplicated_data AS ( -- 第一步:去除完全重复的行 SELECT DISTINCT Id, Amount, Item FROM table_1 ), calc_id_total AS ( -- 第二步:按ID分区计算总金额,同时保留每行的原始金额、商品字段 SELECT Id, Amount, Item, SUM(Amount) OVER (PARTITION BY Id) AS id_total_amount FROM deduplicated_data ) -- 第三步:筛选金额等于ID总金额的行,即为未抵消的目标行 SELECT Id, Amount, Item FROM calc_id_total WHERE Amount = id_total_amount;
原思路关联版(和你最初构思逻辑完全一致)
如果严格按照你最初想的「算完总和再关联回去」的逻辑写,代码如下,相比上面的版本多了一次关联操作,数据量大的时候性能会稍差:
WITH deduplicated_data AS ( SELECT DISTINCT Id, Amount, Item FROM table_1 ), id_total AS ( SELECT Id, SUM(Amount) AS total_amount FROM deduplicated_data GROUP BY Id ) SELECT d.Id, d.Amount, d.Item FROM deduplicated_data d INNER JOIN id_total t ON d.Id = t.Id WHERE d.Amount = t.total_amount;
运行结果
两段代码执行后都会返回你期望的2条结果:
- ID='1',Amount=28,Item='C'
- ID='2',Amount=18,Item='F'
内容的提问来源于stack exchange,提问作者reemas
相关产品推荐
相关产品推荐

