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

PostgreSQL中如何对非连续数值分组求MIN()与MAX()?

识别连续数值段的SQL解决方案

这是个很常见的连续数值分组问题——常规的MIN/MAX聚合会把整个分组的数值范围合并,完全掩盖中间的间隙。我们可以借助窗口函数来标记出每个连续的数值段,再进行聚合就能得到你想要的结果。

核心思路

连续的数值有个关键特点:如果在目标分组内按number排序,用number减去它的行号,得到的差值会是固定的。比如你的示例数据:

  • 第一组连续数19988-19991:19988-1=19987,19989-2=19987,…,19991-4=19987,差值完全一致
  • 第二组22001-22002:22001-5=21996,22002-6=21996,差值一致
  • 第三组26007-26010同理,差值也会统一

这个差值就是我们用来区分不同连续段的标记,基于它再和你的目标分组字段一起聚合,就能得到每个段的起止数值和数量。

完整SQL语句

假设你的表名为transaction_details,可以用如下查询:

WITH segment_marker AS (
    SELECT 
        parent_id,
        transaction_code,
        way_to_pay,
        type_of_receipt,
        unit_price,
        period,
        series,
        number,
        -- 计算连续段的分组标记
        number - ROW_NUMBER() OVER (
            PARTITION BY parent_id, transaction_code, way_to_pay, type_of_receipt, unit_price, period, series
            ORDER BY number
        ) AS group_id
    FROM transaction_details
)
SELECT 
    parent_id,
    transaction_code,
    way_to_pay,
    type_of_receipt,
    unit_price,
    period,
    series,
    MIN(number) AS number_from,
    MAX(number) AS number_to,
    COUNT(number) AS total_numbers
FROM segment_marker
GROUP BY 
    parent_id,
    transaction_code,
    way_to_pay,
    type_of_receipt,
    unit_price,
    period,
    series,
    group_id
ORDER BY 
    parent_id,
    number_from;

语句解释

  1. CTE部分(segment_marker):给每个目标分组(你指定的7个字段)内的行按number排序,计算group_id作为连续段的唯一标记。
  2. 外层聚合:用原分组字段+group_id分组,聚合得到每个连续段的起始值(MIN(number))、结束值(MAX(number))和数量(COUNT(number))。
  3. 排序:最后按parent_id和number_from排序,让结果和你期望的格式完全匹配。

把你的示例数据代入这个查询,就能精准得到你想要的三个连续段的结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:19:25