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

如何在不使用JOIN的情况下实现按分组去重计数与全局去重计数的占比计算

解决方法:无需JOIN实现全局唯一值占比统计

确实很多主流SQL引擎(比如MySQL 8.x之前的版本、部分数据库分支)不支持在窗口函数中直接使用COUNT(DISTINCT),不过我们可以通过嵌套窗口函数+子查询的方式绕开这个限制,完全不需要使用JOIN。下面给你两种实用的方案:

方案一:利用ROW_NUMBER标记全局唯一值

SELECT 
    id,
    COUNT(DISTINCT value) AS distinct_count,
    SUM(CASE WHEN rn = 1 THEN 1 ELSE 0 END) OVER () AS total_distinct,
    ROUND(COUNT(DISTINCT value) / SUM(CASE WHEN rn = 1 THEN 1 ELSE 0 END) OVER (), 3) AS percentage
FROM (
    -- 给每个value的首次出现标记rn=1,重复出现的标记为大于1的数
    SELECT 
        id,
        value,
        ROW_NUMBER() OVER (PARTITION BY value ORDER BY id) AS rn
    FROM have
) t
GROUP BY id;

逻辑说明:

  1. 内层子查询通过ROW_NUMBER() OVER (PARTITION BY value)给每个重复的value分配序号,只有第一次出现的value会得到rn=1。
  2. 外层查询用SUM(CASE WHEN rn=1 THEN 1 ELSE 0 END) OVER ()统计所有rn=1的数量,也就是全局唯一value的总数(对应你要的total_distinct=6)。
  3. 最后按id分组统计每个分组的唯一值数量,再计算占比并保留三位小数。

方案二:用DENSE_RANK获取全局唯一值总数

WITH distinct_pairs AS (
    -- 先提取所有不重复的(id, value)组合
    SELECT DISTINCT id, value FROM have
),
ranked_values AS (
    SELECT 
        id,
        value,
        -- 给每个唯一的value分配连续排名
        DENSE_RANK() OVER (ORDER BY value) AS value_rank
    FROM distinct_pairs
)
SELECT 
    id,
    COUNT(value) AS distinct_count,
    MAX(value_rank) OVER () AS total_distinct,
    ROUND(COUNT(value) / MAX(value_rank) OVER (), 3) AS percentage
FROM ranked_values
GROUP BY id;

逻辑说明:

  1. 第一个CTEdistinct_pairs先过滤掉每个id下重复的value,得到所有唯一的(id, value)对。
  2. 第二个CTEranked_values用DENSE_RANK()给每个全局唯一的value分配连续的排名,全局最大的排名值就是所有唯一value的总数。
  3. 最后按id分组统计每个分组的唯一值数量,结合全局总数计算占比。

这两种方案都能完美输出你期望的结果,而且兼容性很好,支持绝大多数现代SQL引擎(MySQL 8+、PostgreSQL、SQL Server、Oracle等)。

内容的提问来源于stack exchange,提问作者Grizzly2501

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 16:03:12