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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 06:27:03