每月交易二:批准和退单放在一起统计
LeetCode 1205 · UNION ALL 合并事件、条件聚合、过滤全零行
面试怎么回答
我把退单关联原交易拿到国家和金额,按退单日期构造成 chargeback 事件,和交易表 UNION ALL 成一张事件流水,再按月份、国家条件聚合出批准和退单的笔数、金额,HAVING 去掉全零行。把不同来源的事件统一成同一个结构再聚合,是做多事件指标的通用办法。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
交易表记录交易,退单表记录某笔交易后来发生了退单(退单日期和交易日期不同)。按「月份 + 国家」统计已批准交易的笔数和金额、退单的笔数和金额;四个值全为 0 的行不输出。
表结构
- Transactions:id(主键)、country、state(approved / declined)、amount、trans_date
- Chargebacks:trans_id(对应交易 id)、trans_date(退单日期)
思路
难点在于退单要按「退单日期」归月,国家和金额却要从原交易里拿。做法是把退单关联交易表,构造成和交易表同样结构的「退单事件」(状态记为 chargeback、日期用退单日期),再和交易表 UNION ALL,最后按月份和国家做条件聚合,HAVING 排除全零行。
参考解法
select
date_format(trans_date, '%Y-%m') month,
country,
sum(state = 'approved') approved_count,
sum(if(state = 'approved', amount, 0)) approved_amount,
sum(state = 'chargeback') chargeback_count,
sum(if(state = 'chargeback', amount, 0)) chargeback_amount
from (
select * from transactions
union all
select id, country, 'chargeback' state, amount, c.trans_date
from chargebacks c left join transactions t
on c.trans_id = t.id
) tmp
group by month, country
having approved_amount or chargeback_amount
易错点
- 退单要用退单日期归月,不是原交易日期。
- 只从交易表出发 LEFT JOIN 退单,会让退单按交易月份统计,而且某个月只有退单没有交易时这一行会缺失。