如何根据PostgreSQL中的行差异有条件地合并行?

时间:2017-06-10 13:53:19

标签: sql postgresql merge rows difference

我已经解决了一些相关的合并问题,但我的问题与现有问题略有不同。我的PostgreSQL 9.5数据库中有一个表,包含四列,即Segment(唯一组),height(数字),lower_limit(数字)和upper_limit(数字)。样本数据如下:

Segment height  lower_limit upper_limit
A       19.3    112         142
A       19.3    142         172
A       20.3    172         202
A       20.3    202         232
A       19.3    232         262
A       19.3    262         292
B       22.1    203         233
B       22.1    233         263
B       22.1    263         293
B       22.1    293         323
B       22.1    323         353
B       22.1    353         383
C       18.9    136         166
C       18.9    166         196
C       18.9    196         226
C       27.1    286         316
C       27.1    316         346
C       6.5     346         376
C       6.5     376         406

我需要根据高度值的差异有条件地合并行。我会尝试分步解释:

  • 从第一个高度开始,检查前一行和后一行之间的差异是否小于或等于1
  • 如果条件满足合并那些具有合并行的第一行和上限的下限的行
  • 如果所有行都合并在一个组中,则选择最常见的高度,其上限为上一个合并行的上限和下限
  • 为其他群体重复此操作

    基于以上所述,所需的输出可能如下:

    Segment height lower_limit upper_limit A 19.3 112 292 B 22.1 203 383 C 18.9 136 226 C 27.1 286 346 C 6.5 346 406

有人可以帮助我,以便根据身高差异值有条件地合并行吗?

2 个答案:

答案 0 :(得分:1)

假设lower_limit列可用于排序,您可以使用

TypeError: Object of type 'Object1' is not JSON serializable

答案 1 :(得分:1)

  -- setting reset points
  with  b as
  (
      select segment, height, lower_limit, upper_limit, 
             case when lag(height) over (partition by segment order by segment, height) is null
                       or abs(height - lag(height) over (partition by segment order by segment, height)) > 1
                  then 1 end as is_reset
      from   foo
  )
     -- setting groups
     , c as
     (
         select segment, height, lower_limit, upper_limit,
                sum(is_reset) over (order by segment, height) as grp
         from b
     )
       -- finding most common height
           select segment, mode() within group (order by height),
                  min(lower_limit) as lower_limit, 
                  max(upper_limit) as upper_limit
           from c
           group by segment, grp
segment |  mode | lower_limit | upper_limit
:------ | ----: | ----------: | ----------:
A       | 19.30 |         112 |         292
B       | 22.10 |         203 |         383
C       |  6.50 |         346 |         406
C       | 18.90 |         136 |         226
C       | 27.10 |         286 |         346

dbfiddle here