T-SQL技术问题:统计左连接左表行数及左连接去重实现
T-SQL问题解答
问题1:如何统计左连接中左表T1的行数?
左连接的特性是会保留左表T1的所有行,不管右表T2有没有匹配的数据,所以统计T1的行数分两种场景来处理:
如果想在查询结果的每一行都带上T1的总行数:
可以用窗口函数COUNT(T1.EMAIL) OVER (),它会直接计算T1的所有行数(因为你的T1是用UNION拼接的,本身已经去重了,所以COUNT的结果就是唯一邮箱的数量)。把它加到你的查询里就行:SELECT T1.EMAIL, T2.BILLG_STATE_CD, T2.BILLG_ZIP_CD, T2.ord_creatd_dt, COUNT(T1.EMAIL) OVER () AS T1_Total_Rows -- 新增这行统计左表总行数 FROM (SELECT EMAIL FROM SJ_FPQ_Q1_19 UNION SELECT EMAIL FROM SJ_FPQ_Q2 UNION SELECT email AS EMAIL FROM Amber_10182019) AS T1 LEFT JOIN ORD_MSTR As T2 ON T1.EMAIL = T2.EMAIL_ADDR WHERE T2.ord_creatd_dt > DATE '2018-01-01' AND T2.ord_creatd_dt < DATE '2019-11-08'如果只是单纯想得到T1的总行数(不需要和连接结果一起返回):
直接查询T1的记录数就可以,简单直接:SELECT COUNT(*) AS T1_Total_Rows FROM (SELECT EMAIL FROM SJ_FPQ_Q1_19 UNION SELECT EMAIL FROM SJ_FPQ_Q2 UNION SELECT email AS EMAIL FROM Amber_10182019) AS T1
问题2:每个T1邮箱仅返回一条结果,处理T2的重复数据
你提到的PARTITION BY思路完全正确,只是可能没找对语法位置。这里核心是先给T2中每个邮箱的记录做排序标记,只保留最新的那一条,再和T1做连接。我给你两种可靠的实现方式:
方式1:用ROW_NUMBER()窗口函数(推荐,灵活处理多重复场景)
这种方法可以精准控制取哪一条记录,比如最新订单,或者最大订单ID的记录:
SELECT T1.EMAIL, T2_filtered.BILLG_STATE_CD, T2_filtered.BILLG_ZIP_CD, T2_filtered.ord_creatd_dt FROM ( SELECT EMAIL FROM SJ_FPQ_Q1_19 UNION SELECT EMAIL FROM SJ_FPQ_Q2 UNION SELECT email AS EMAIL FROM Amber_10182019 ) AS T1 LEFT JOIN ( SELECT EMAIL_ADDR, BILLG_STATE_CD, BILLG_ZIP_CD, ord_creatd_dt, -- 按邮箱分组,组内按订单日期降序排,最新的记录会被标记为1 ROW_NUMBER() OVER (PARTITION BY EMAIL_ADDR ORDER BY ord_creatd_dt DESC) AS row_num FROM ORD_MSTR WHERE ord_creatd_dt > DATE '2018-01-01' AND ord_creatd_dt < DATE '2019-11-08' ) AS T2_filtered ON T1.EMAIL = T2_filtered.EMAIL_ADDR -- 只保留每个邮箱的第一条记录,同时保留T1中无匹配的邮箱 WHERE T2_filtered.row_num = 1 OR T2_filtered.row_num IS NULL
如果遇到同一个邮箱同一天有多个订单的情况,你可以在ORDER BY里再加一个排序字段,比如ORDER BY ord_creatd_dt DESC, ORD_ID DESC,确保只取唯一的一条。
方式2:用MAX(ord_creatd_dt)关联
如果你更倾向于用MAX日期的方式,也可以先找出每个邮箱的最新订单日期,再回表关联T2获取地址信息:
SELECT T1.EMAIL, T2.BILLG_STATE_CD, T2.BILLG_ZIP_CD, T2.ord_creatd_dt FROM ( SELECT EMAIL FROM SJ_FPQ_Q1_19 UNION SELECT EMAIL FROM SJ_FPQ_Q2 UNION SELECT email AS EMAIL FROM Amber_10182019 ) AS T1 LEFT JOIN ( -- 先获取每个邮箱的最新订单日期 SELECT EMAIL_ADDR, MAX(ord_creatd_dt) AS latest_dt FROM ORD_MSTR WHERE ord_creatd_dt > DATE '2018-01-01' AND ord_creatd_dt < DATE '2019-11-08' GROUP BY EMAIL_ADDR ) AS T2_max ON T1.EMAIL = T2_max.EMAIL_ADDR -- 关联回T2拿到对应的地址数据 LEFT JOIN ORD_MSTR AS T2 ON T2_max.EMAIL_ADDR = T2.EMAIL_ADDR AND T2_max.latest_dt = T2.ord_creatd_dt
不过这种方法要注意,如果同一个邮箱在latest_dt当天有多个订单,还是会返回多条记录,这时候就需要额外的过滤条件,或者改用第一种方式更稳妥。
内容的提问来源于stack exchange,提问作者Amber Williams
相关产品推荐
相关产品推荐

