2011-08-11 2 views
1

당신이 중재자이고 더 나은 제목을 알고 있다면 지저분한 제목에 대해 사과하십시오.어떻게 테이블을 결합하여 오른쪽 테이블 값이 왼쪽 테이블의 두 개의 다른 행에 종속되도록 하시겠습니까?

말, 우리는 내가이 간격 테이블에서 필드 "이후"A "발"에 대한 하한 될 것이라고 그래서 가입하게하려면 두 개의 SQL 테이블

 
intervals   vals  
--------   -------  
since    val   
--------   -------  
1     1   
4     2   
8     3 
20     4   
...    ... 
500    100 

있습니다. 그리고 "이후"더 큰 "val"이없는 값은 나타나지 않습니다. 내가 원하는 것을보십시오 :

 
since val 
-------------- 
1  1 
1  2 
1  3 
4  4 
4  5 
4  6 
4  7 
8  8 
8  9 
..... 

일반적인 SQL에서는 어떻게합니까? Postgres 전용 솔루션도 적합합니다.

+0

RhodiumToad의 쿼리가 더 좋습니다. http://www.postgresql.org/docs/9.0/static/tutorial-window.html – Ketema

답변

2

신용을 #postgresql의 RhodiumToad

SELECT * 
FROM vals v 
JOIN (select since 
       , lead(since) over (order by since) as "end" 
     from intervals) s 
     ON (v.val >= s.since 
      AND ((v.val >= s."end") IS NOT TRUE) 
      ) 
; 
+0

쿼리 계획 : http://pastebin.com/bX3bywN4 – Ketema

+0

감사합니다. 케타 마. 꽤 인상적인 차이. 이제 내 테이블이 꽤 커서 질의 실행이 수십 초 동안 지속되므로이 솔루션을 사용하는 것처럼 느껴진다. – zamza

+0

@zamza : 대부분의 대형 데이터베이스는 창 기능 (예 :'lead()')에 최적화되어있어 초보자들에게는 혼란을 줄 수 있지만 성능상의 이점이 있습니다. 이것은 단지 하나의 해결책이었습니다. 더 최적화 할 수있는 방법이있을 것이라고 생각합니다. 그러나 어제 내 테스트 시스템이 중단되었습니다. – vol7ron

3

"복수 행"이라고 생각하지 말고 범위 인으로 생각하십시오.

이 당신이 원하는 것을 수행합니다

select i.since, v.val 
from intervals i 
join vals v on v.val between i.since and 
    (select min(since) - 1 from intervals where since > i.since) 
order by 1, 2; 

테스트 코드 (OP의 질문에 따라 포스트 그레스에서 실행) :

create table intervals (since int); 
create table vals (val int); 
insert into intervals values (1), (4), (8), (20), (500); 
insert into vals values (1), (2), (3), (4), (5), (6), (7), (8), (9), (100); 

출력 쿼리 위에서 님의

1 1 
1 2 
1 3 
4 4 
4 5 
4 6 
4 7 
8 8 
8 9 
20 100 
+1

쿼리 계획 : http://pastebin.com/r0CNrDYx – Ketema

관련 문제