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

PostgreSQL非精确GROUP BY聚合:按阈值分组求均值与计数

PostgreSQL 动态阈值分组聚合解决方案

一、窗口函数实现方案(子查询/CTE方式)

这是处理这类传递性聚类分组的常规方案,通过窗口函数标记新组起始、生成组ID后完成聚合:

WITH grouped_rows AS (
  SELECT
    value,
    -- 标记当前行是否为新组起始:与前一行value差超过阈值则触发新组
    SUM(CASE WHEN value - LAG(value, 1, value) OVER (ORDER BY value) > 1.5 THEN 1 ELSE 0 END) 
      OVER (ORDER BY value) AS group_id
  FROM foo
)
SELECT
  ROUND(AVG(value), 2) AS avg_value,
  COUNT(*) AS row_count
FROM grouped_rows
GROUP BY group_id
ORDER BY avg_value;

逻辑说明:

  • LAG(value, 1, value):获取当前行的前一行value,第一行用自身值避免NULL
  • 若当前行与前一行的value差超过阈值1.5,标记为1(新组开始),否则为0
  • SUM(...) OVER (ORDER BY value):累加标记值生成唯一组ID,同一聚类组的行ID一致
  • 按组ID聚合后得到每组的均值和行数

执行结果:

avg_value | row_count
-----------+-----------
       2.0 |         4
       7.0 |         4

二、近似无分子查询的分桶方案(仅适用于特定场景)

严格来说,传递性聚类无法完全脱离子查询/CTE,因为组划分依赖相邻行的比较。但如果数据的组间间隔明显大于阈值、组内数值范围稳定,可以用固定分桶表达式直接GROUP BY:

SELECT
  ROUND(AVG(value), 2) AS avg_value,
  COUNT(*) AS row_count
FROM foo
GROUP BY FLOOR((value - 0.5) / 3) -- 3为阈值的2倍,0.5为偏移量,适配当前示例数据
ORDER BY avg_value;

注意:

该方案是硬编码分桶规则,仅适配当前示例数据。若后续出现4这类处于组边缘的值,会错误划分分组,不具备通用性。

三、递归CTE实现方案(可选)

如果需要更灵活处理复杂的连通分量分组,可使用递归CTE:

WITH RECURSIVE clusters AS (
  -- 初始化:每行作为独立初始簇
  SELECT id, value, id AS cluster_id FROM foo
  UNION ALL
  -- 合并簇:将与当前簇内value差<=1.5的行合并到同一簇
  SELECT c.id, c.value, cl.cluster_id
  FROM clusters c
  JOIN foo cl ON ABS(c.value - cl.value) <= 1.5 AND c.cluster_id != cl.id
)
SELECT
  ROUND(AVG(value), 2) AS avg_value,
  COUNT(DISTINCT id) AS row_count -- 去重避免递归导致的重复统计
FROM clusters
GROUP BY cluster_id
ORDER BY avg_value;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 18:29:55