为何分欺诈状态统计的唯一Call_ID总数与联合查询结果不符?
这个差异的核心原因很明确:同一个Call_ID可能对应多条不同Fraud_Status的记录,你分状态统计时,会把跨多个状态的Call_ID重复计入不同分组,但联合查询里每个Call_ID只会被统计一次。
举个实际例子:假设某个Call_ID在数据里同时存在Fraud_Status=''和Fraud_Status='Genuine'的记录,且两条都满足时间和Risk_Score的筛选条件。那它会在第一个空状态查询、第三个Genuine状态查询里各被算一次,但在联合查询里只会被统计一次。这类跨状态的Call_ID越多,总和与联合查询结果的差距就越大。
验证猜想的查询
你可以运行下面的SQL,找出那些在符合条件的记录里对应多个不同Fraud_Status的Call_ID:
SELECT Call_ID, COUNT(DISTINCT Fraud_Status) AS distinct_status_count FROM DATA WHERE EntryTimestamp < '2018-04-20 18:00:00.000' AND CAST(Risk_Score AS FLOAT) < 80 GROUP BY Call_ID HAVING COUNT(DISTINCT Fraud_Status) > 1
这个查询返回的记录数,应该正好等于你的总和与联合查询结果的差值(2,738,582 - 2,733,076 = 5,506),这些就是被重复计算的Call_ID。
两种正确的统计方式
1. 保留重叠统计(匹配原需求字面逻辑)
如果你的需求就是统计每个Fraud_Status下,至少有一条该状态记录且符合条件的唯一Call_ID数量,那你原来的分状态查询是正确的,但要明确:这些Call_ID是存在重叠的——同一个Call_ID可能出现在多个状态的统计结果里。
2. 每个Call_ID仅归属一个状态(避免重复计算)
如果你的需求是让每个Call_ID只被统计到一个Fraud_Status分组里(比如按业务优先级归类),那你需要先给每个Call_ID确定唯一的状态,再统计。比如我们可以给Fraud_Status设定优先级(比如Fraud > Genuine > Inconclusive > Unknown > 空字符串),然后取每个Call_ID的最高优先级状态:
WITH ranked_calls AS ( SELECT Call_ID, Fraud_Status, -- 给不同状态设定优先级,数字越小优先级越高 ROW_NUMBER() OVER ( PARTITION BY Call_ID ORDER BY CASE Fraud_Status WHEN 'Fraud' THEN 1 WHEN 'Genuine' THEN 2 WHEN 'Inconclusive' THEN 3 WHEN 'Unknown' THEN 4 ELSE 5 END ) AS status_rank FROM DATA WHERE EntryTimestamp < '2018-04-20 18:00:00.000' AND CAST(Risk_Score AS FLOAT) < 80 ) SELECT Fraud_Status, COUNT(Call_ID) AS unique_call_count FROM ranked_calls WHERE status_rank = 1 -- 只保留每个Call_ID的最高优先级状态 GROUP BY Fraud_Status ORDER BY unique_call_count DESC;
这个查询的结果总和会等于联合查询的2,733,076,因为每个Call_ID只被统计一次。
内容的提问来源于stack exchange,提问作者Brandon

