主流SQL引擎不支持COUNT(DISTINCT)直接用于窗口函数,因去重逻辑与窗口累积语义冲突;可用ARRAY_AGG+ARRAY_DISTINCT模拟累计去重,适用于中小规模数据。
为什么 COUNT(DISTINCT ...) 不能直接套窗口函数
直接写 SELECT COUNT(DISTINCT user_id) OVER (ORDER BY dt ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) 会报错——主流 SQL 引擎(如 PostgreSQL、MySQL 8.0+、Spark SQL)都不支持对 COUNT(DISTINCT) 使用窗口函数。本质是去重逻辑与窗口的累积语义冲突:窗口需要逐行维护状态,而 DISTINCT 是聚合操作,不可拆分。
用 ARRAY_AGG + ARRAY_DISTINCT 模拟累计去重(PostgreSQL / Spark SQL)
适用于中小规模数据(日活 user_id 收集为数组,再去重取长度:
SELECT dt, ARRAY_LENGTH(ARRAY_DISTINCT(ARRAY_AGG(user_id) OVER (ORDER BY dt)), 1) AS cumu_unique_users FROM events GROUP BY dt;
-
ARRAY_AGG必须配合GROUP BY dt,否则同一日期多行会重复累加 - PostgreSQL 需要
ARRAY_DISTINCT(v14+),旧版可用ARRAY(SELECT DISTINCT unnest(...))替代,但性能差 - Spark SQL 中对应函数是
size(array_distinct(collect_list(user_id))),注意collect_list不去重,必须套array_distinct - 内存风险:若某天用户量极大(如千万级),
ARRAY_AGG可能 OOM
用自连接 + 子查询实现精确累计(通用兼容方案)
不依赖高级数组函数,所有 SQL 引擎都支持,但需注意性能和去重逻辑边界: