2016-11-28 7 views
3

나는 PLSQL의 고급 주제에 익숙하지 않기 때문에 누군가 나를 도와 줄 수 있기를 바랍니다.Oracle에서 재귀 쿼리

문제 : 관리자와 사용자간에 메시지가 전송 된 테이블이 있습니다. 테이블에는 동일한 테이블 message_id 필드에 FK가있는 message_parent가 있습니다. 필드가 채워지면 메시지가 이전 메시지에 대한 응답으로 전송되었음을 의미합니다. 동일한 대화에 속한 모든 메시지를 선택하여 표시해야합니다. 단일 쿼리로이 작업을 수행 할 수 있습니까? 아니면 이러한 종류의 논리를 처리하는 절차가 필요합니까? 내가 알고있는 것처럼 내가 검색하고있는하여 MESSAGE_ID는 항상

예를 변화이기 때문에, 재귀 할 필요가 메시지 테이블 :

|message_id|parent_id|message_content| 
|----------|---------|---------------| 
|101  |100  | foo   | 
|100  |97  | bar   | 
|99  |(null) | Left out  | 
|97  |(null) | baz   | 

그래서 올바른 쿼리 MESSAGE_CONTENT은 반환해야합니다 선택 "baz", "bar"및 "foo"이지만 "이탈 한"것은 아닙니다 (baz는 원래 메시지이므로). 예를 들어 있다면 간단합니다. 함께 묶을 수있는 두 개의 메시지 만 동일한 '스레드'에있는 모든 메시지를 연결하지만 parent_id가 끊임없이 이동하는 thread_id 열은 문제를 파악하는 데 어려움을 겪고 있습니다.

+0

사용중인 Oracle 버전은 무엇입니까? –

+0

12c 일반용 – taurijuhkam

답변

5

는 오라클에서이 쉽게이 트리를 산책 위에서 아래에 CONNECT BY

select message_id, parent_id, message_content 
from messages 
start with message_id = 97 -- this is the root of your conversation 
connect by prior message_id = parent_id; 

사용하여 수행됩니다.

select message_id, parent_id, message_content 
from messages 
start with message_id = 100 -- this is the root of your conversation 
connect by prior parent_id = message_id; -- this now goes "up" in the tree 
+0

typo? 나는 당신이 다음을 의미한다고 생각한다.'connect by prior MESSAGE_id = parent_id;'?? – Ditto

+0

@Ditto : 예, 고마워요. –

+1

이것은 주로 트릭을하는 것처럼 보이지만, 대화의 루트의 이드를 모른다면 어떨까요? 대부분의 경우 실제로는 뒤로 -> 사용자가 메시지를 선택하고 이전 메시지를 표시해야합니다. 그래서 중간 또는 마지막 메시지 아이디 중 하나를 알고 있으며 나는 뒤로 가야합니다. 시작 문자를 현재 메시지 ID로 바꾸면 이전 메시지는 표시되지 않지만 현재 메시지 다음 문자는 표시되지 않습니다. E, g 알아요 message_id 100은 bar입니다 어떻게 mnessage_id 97, baz – taurijuhkam

1

단일 message_id의 기반으로 전체 메시지 컨텍스트를 얻으려면, 당신은 사용할 수 있습니다 : 당신이 루트에 하나의 메시지에서 트리를 걸어하려면 start withconnect by 부분을 변경

두 개의 계층 적 쿼리. 하나는 메시지 트리를 현재 메시지 down에서 루트로 이동하고 두 번째는 루트에서 나뭇잎으로 뒤로 걸어갑니다. 현재 MESSAGE_ID 가정하면 100 (101 또는 97의 값이 동일한 최종 결과있을 것입니다하지만), 다음 쿼리는 (모든 '탈락'제외) 모든 관련 메시지를 반환하는 것입니다 : I '는 down 쿼리에서

with msgs(message_id, parent_id, message_content) as (
    select 101, 100, 'foo' from dual union all 
    select 100, 97, 'bar' from dual union all 
    select 99, null, 'Left out' from dual union all 
    select 97, null, 'baz' from dual 
), down as (
    select message_id start_id 
     , CONNECT_BY_ROOT message_id curr_id 
    from msgs 
    where connect_by_isleaf = 1 
    start with message_ID = 100 
connect by message_ID = prior parent_ID 
) /* up */ 
select level lvl 
     , case message_id when curr_id then '*' end curr 
     , msgs.* 
    from msgs, down 
    start with message_ID = start_id 
connect by prior message_ID = parent_ID 
    order siblings by message_id; 

ve는 루트 메시지 노드 (connect_by_isleaf) 만 반환하도록 제한하고 현재 메시지를 별표로 표시하는 열을 포함하는 up 쿼리에 참조 용으로 curr_id이라는 현재 message_id를 포함 시켰습니다 .