2016-11-28 17 views
3

私はPLSQLのより高度なトピックに新しいので、うまくいけば誰かが私を助けることができます。Oracleでの再帰的クエリ

問題: 管理者とユーザーの間でメッセージが送信されるテーブルがあります。テーブルには、同じテーブルのmessage_idフィールドにFKを持つmessage_parentがあります。フィールドにデータが入力されている場合は、メッセージが前のメッセージへの返信として送信されたことを意味します。同じ会話の一部であるすべてのメッセージを選択して表示する必要があります。単一のクエリでこれを行うことはできますか、またはそのような種類のロジックを処理するためのプロシージャが必要ですか?

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

のでMESSAGE_CONTENTを選択し、正しいクエリが返す必要があります:私は理解したよう私が探していたことでMESSAGE_IDは、常に

メッセージテーブルを変更しているので、それは、再帰的にする必要があります"baz"、 "bar"、 "foo"ではなく "Left out"(bazは元のメッセージなので)。 これは、例えば、一緒に結びつけることができるメッセージは2つだけです。同じ「スレッド」内のすべてのメッセージをリンクするが、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?私はあなたが '前のMESSAGE_id = parent_idで接続する'という意味だと思う? – Ditto

+0

@Ditto:はい、ありがとう。 –

+1

これは主にトリックを行うようですが、私が会話のルートのIDを知らないとどうなりますか?ほとんどの場合、実際にはbackwards-> userがメッセージを選択し、以前のメッセージを表示する必要があります。だから、私は中間のmessage_idの最後か一つを知っているので、私は後ろに行く必要があります。 私は現在のメッセージIDで始まるを置き換える場合、私は以前のメッセージを取得しませんが、現在のメッセージの後のものです。 E、g私はmessage_id 100がbarであることを知っていますmamesage_id 97、baz – taurijuhkam

1

単一message_idのオフに基づいて、メッセージ全体のコンテキストを取得するには、使用することができます:あなたがルートに単一のメッセージからツリーを歩くしたい場合は、start withconnect by一部を変更

2つの階層クエリ。現在のメッセージdownからルートにメッセージツリーを移動し、2番目のルートはルートから葉までupを返します。 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; 

:(101または97の値が同じ最終結果を有するであろうが)現在のMESSAGE_IDが100であると仮定すると、次のクエリは、関連するすべてのメッセージ(すべての「除外」を除く)を返しますveは、start_idがルートメッセージになるようにルートメッセージノード(connect_by_isleaf)のみを返すように制限しました。upクエリで参照用にcurr_idという現在のmessage_idが含まれていましたが、現在のメッセージにアスタリスク。