2017-06-10 7 views
0

私はいくつかの関連する合併問題を抱えていますが、私の問題は既存の問題と若干異なります。私は、セグメント(一意のグループ)、高さ(数値)、lower_limit(数値)、upper_limit(数値)の4つの列を含むPostgreSQL 9.5データベースのテーブルを持っています。サンプルデータは次のとおりです。PostgreSQLの行の違いに基づいて行を条件付きでマージするにはどうすればよいですか?

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
  • に等しい場合、条件満足が最初の行の下限とこれらの行をマージするかどうかを確認しますマージされた行の上限
  • すべての行がグループにマージされるならば、最も一般的な高さを選択し、最後のマージされた行の最初及び上限の下限と
  • リピートこの他のグループのため

    基づきO私は条件付きで高さの差値に基づいて行をマージすることができるように誰かが私を助けることができる

    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

:nは上記の、所望の出力は次のようになるだろうか?

+0

使用することができます発注のために使用することができますか? –

+0

コードの最後にgrp行を追加しました。私は希望の出力に応じて5行を得ていますが、この方法では:C、A、B、C、C希望の出力を見てください。 –

+0

'segment、grp 'による注文の追加 –

答えて

1

と仮定すると、lower_limitでの列には、あなたが順序を指定する欄がある

select segment,mode() within group(order by height),min(lower_limit),max(upper_limit) 
from (select t.* 
     ,sum(case when abs(height-prev) <= 1 then 0 else 1 end) over(partition by segment order by lower_limit) as grp 
     from (select t.* 
      ,lag(height) over(partition by segment order by lower_limit) as prev 
      from tbl t 
      ) t 
    ) t 
group by segment,grp 
+0

私は最後の2行を修正しました。私は追加しました:grpによるグループ、grpによるセグメントのセグメント、セグメント。私は必要に応じてA、B、C、C、Cを得た。すべての値は、最初のセグメントAを除いて問題ありません。それは、20.3、112、292を与えます。 –

+0

@ JibranKhan ..編集をチェックする 'モード'は、セグメントごとに最も高い高さとgrp..whichを必要とするものです。 –

+0

ありがとうございました –

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

+0

ありがとうございました。私はあなたのコードをdbfiddleでテストしました。そこではうまくいった。私のPostgresデータベースには全く同じテーブルがありますが、A、B、C、C、C、Cの6つの行が返されます。1行C(18.9,136,226)が2回返されます。どんな考え? –

+0

最初の選択を実行し、正しい順序を返すようにします。 – McNets

+0

まあ、私はすべてのコードを改造して、私が間違いを犯していないことを確かめるが、同じ結果を残している。 –

関連する問題