SQL加DISTINCT仍有重复行?如何仅保留每个ClientID的首条交易记录
原有SQL的问题定位
DISTINCT的作用是对SELECT返回的整行全字段组合去重,并非针对ClientID单独去重。只要同一ClientID对应的Manager/RegistrationDate/DateOfFirstTransaction字段存在差异,哪怕ID重复,也会被判定为不同行保留,无法实现按ClientID去重的目标。- 子查询中编写的
ROW_NUMBER() OVER(PARTITION BY bbt.user_id ORDER BY bbt.created_at)窗口函数完全未发挥作用:你将row_num字段加入了外层GROUP BY的分组维度,导致同一ClientID下每笔对应不同序号的交易都会被拆分成独立行。可以在外层查询临时把row_num字段查出来直观验证:同一个ClientID对应的结果行,row_num会按交易笔数从1开始逐次递增,每一行的字段组合因为row_num的差异本身就不重复,DISTINCT自然没有过滤效果。 - 外层的CASE判断、多余的
Email/金额字段属于冗余逻辑:子查询已经对交易表的时间范围做了硬过滤,不存在超出2021-01-01至2021-04-01区间的交易值,再加CASE判断只会增加字段值的差异维度,进一步阻碍去重。
修正后的实现方案
核心逻辑是利用已经编写好的窗口函数,直接提取每个ClientID排序后的第一条记录,不需要多余的DISTINCT和GROUP BY:
SELECT "ClientID", "Manager", "RegistrationDate", "Date of transaction" AS DateOfFirstTransaction FROM ( SELECT uu.id AS "ClientID", uu.created_at AS "RegistrationDate", initcap(split_part(man.email,'@',1)) AS "Manager", bbt.created_at AS "Date of transaction", -- 按ClientID分组,按交易时间升序标记行序号:1代表该客户的第一笔有效交易 ROW_NUMBER() OVER(PARTITION BY uu.id ORDER BY bbt.created_at) AS row_num FROM users_user uu LEFT JOIN users_user man ON uu.account_manager_id = man.id LEFT JOIN ( SELECT * FROM billing_balancetransaction WHERE executed_at IS NOT NULL AND payment > 0 AND created_at BETWEEN '2021-01-01' AND '2021-04-01' AND created_at IS NOT NULL ) bbt ON bbt.user_id = uu.id WHERE uu.created_at >= '2021-01-01' AND uu.created_at < '2021-04-01' AND uu.account_manager_id IN (24250,24252,24253) ) t -- 核心过滤规则:仅保留每个ClientID的第一条标记记录 WHERE row_num = 1;
该逻辑同时兼容无有效交易的客户场景:这类客户关联的交易字段为NULL,窗口函数同样会为其标记
row_num=1,会被正常保留在结果中,和你原本期望的输出结构完全一致。
内容的提问来源于stack exchange,提问作者Yariy Zhlob
相关产品推荐
相关产品推荐

