Oracle SQL:基于CLIENT_ID累计唯一值聚合DAYS列的实现方法
实现Oracle SQL中累计唯一客户的每日统计需求
这个需求核心是计算截至每一天的累计唯一CLIENT_ID数量——每个客户仅在首次出现的日期被统计,后续日期再出现时不会重复计入。下面是两种在Oracle中可行的实现方案:
方案一:基于客户首次出现日期的统计
先提取每个客户第一次出现的日期,再统计每一天及之前所有首次出现的客户总数:
WITH first_occurrence AS ( -- 找出每个CLIENT_ID的首次出现日期 SELECT CLIENT_ID, MIN(DAY) AS first_day FROM DAY_CLIENT GROUP BY CLIENT_ID ) SELECT d.DAY AS DAYS, COUNT(f.CLIENT_ID) AS CNT_CLIENT_ID -- 取出所有不重复的日期,确保每一天都能被统计到 FROM (SELECT DISTINCT DAY FROM DAY_CLIENT) d -- 关联首次出现记录,统计截止到当前天的所有新客户 LEFT JOIN first_occurrence f ON d.DAY >= f.first_day GROUP BY d.DAY ORDER BY d.DAY;
逻辑说明:
- 借助CTE
first_occurrence计算每个客户的首次访问日期; - 从原表中提取所有不重复的日期,避免遗漏某天的数据;
- 通过左连接将日期与首次出现记录关联,统计每个日期及之前的所有首次出现客户数,得到累计唯一值。
方案二:使用窗口函数标记首次出现并累加
通过窗口函数标记每个客户的首次出现记录,再累加这些标记得到累计值:
SELECT DAY AS DAYS, -- 累加从第一天到当前天的首次出现客户数 SUM(CASE WHEN is_first = 1 THEN 1 ELSE 0 END) OVER (ORDER BY DAY) AS CNT_CLIENT_ID FROM ( SELECT DAY, CLIENT_ID, -- 标记当前记录是否是该客户的首次出现 CASE WHEN ROW_NUMBER() OVER (PARTITION BY CLIENT_ID ORDER BY DAY) = 1 THEN 1 ELSE 0 END AS is_first FROM DAY_CLIENT ) t GROUP BY DAY ORDER BY DAY;
逻辑说明:
- 内层查询用
ROW_NUMBER()给每个客户的出现记录按日期排序,首次出现的记录序号为1,标记为is_first=1; - 外层按天分组后,用
SUM() OVER (ORDER BY DAY)累加截止到当前天的所有首次出现标记,得到累计唯一客户数。
两种方案都能得到你期望的结果:
DAYS CNT_CLIENT_ID
1 3
2 3
3 4
4 4
内容的提问来源于stack exchange,提问作者Timothy Quiros
相关产品推荐
相关产品推荐

