2011-01-25 49 views
1

選擇重疊度對在我的Postgres數據庫我有一個表3列是這樣的:如何從DB

start | end | sorce 
17 | 23 | A 
150 | 188 | A 
200 | 260 | A 
19 | 30 | B 
105 | 149 | B 
199 | 220 | B 
... 

我想從遞延來源選擇所有的行,其中區(開始到結束) A和B重疊。

UPDATE:

從Postgres的8.4版是更多鈔票與window functions來解決問題。它比join或subselect方法快得多。 Link to postgres wiki

回答

2

這可以用作蠻力方法(我將列range_start和range_end重命名以避免與保留字「end」衝突):

select * 
from t cross join t t2 
where t2.source <> t.source 
     and box(point(t2.range_start,t2.range_start),point(t2.range_end,t2.range_end)) 
      && box(point(t.range_start,t.range_start),point(t.range_end,t.range_end)) 

select * 
from t 
where exists (select 1 from t t2 
       where t2.source <> t.source and box(point(t2.range_start,t2.range_start),point(t2.range_end,t2.range_end)) 
        && box(point(t.range_start,t.range_start),point(t.range_end,t.range_end))) 

然後,您應該能夠使用其主旨在於指數,這可能使其成爲更有效(SEQ掃描+索引掃描):

create index t_range_idx on t using gist (box(point(range_start,range_start),point(range_end,range_end)) 

此功能可能有助於理解通過清理的SQL:

create function range(not_before int, not_after int) returns box 
    strict immutable language sql 
    as $$ select box(point($1,$1),point($2,$2)) $$; 

有了這個,你可以這樣寫:

select * from t where range(range_start,range_end) && range(10,20); 

並注意運營商的意思是「重疊」。

0

如果你想全部配對,然後INNER JOIN A和採用了經典的重疊測試

a.start < b.end and b.start < a.end 

select a.start a_start, a.end a_end, b.start b_start, b.end b_end 
from tbl a 
inner join tbl b on a.start < b.end and b.start < a.end and b.source = 'B' 
where a.source = 'A' 

B如果你不是說來源literally 'A' 和 'B' ,只是它們不同,你可以用下面的代替

select a.start a_start, a.end a_end, b.start b_start, b.end b_end 
from tbl a 
inner join tbl b on a.start < b.end and b.start < a.end and a.source <> b.source 

根據你的de重疊的FINITION,交換<<=(兩次)

  • <:10-20確實重疊20-30
  • <=:10-20 確實重疊20-30
+0

也許`哪裏a.source <> b.source` – araqnid 2011-01-25 11:14:02

+0

@araqnid - 謝謝。更新了條款 – RichardTheKiwi 2011-01-25 11:15:17