2016-11-28 4 views
3

Ich bin etwas neu zu den fortgeschritteneren Themen von PLSQL, also hoffentlich kann mir jemand helfen.Rekursive Abfrage in Oracle

Das Problem: Ich habe eine Tabelle mit Nachrichten zwischen einem Administrator und Benutzern gesendet. Die Tabelle hat ein Message_Parent mit FK für dieselbe Tabelle message_id-Feld: Wenn das Feld ausgefüllt ist, bedeutet dies, dass die Nachricht als Antwort auf eine vorherige Nachricht gesendet wurde. Ich muss alle Nachrichten auswählen, die Teil derselben Konversation sind, und sie anzeigen. Kann dies mit einer einzigen Abfrage durchgeführt werden oder brauche ich eine Prozedur, um mit dieser Art von Logik umzugehen? Wie ich verstehe, braucht es rekursiv zu sein, da die message_id, durch die ich bin immer auf der Suche

Beispiel Nachrichten Tabelle ändert sich:

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

Also die richtige Abfrage auszuwählen sollte message_content zurückkehren "baz", "bar" und "foo", aber nicht "Ausgelassen" (da baz die ursprüngliche Nachricht ist). Dies wäre einfach, wenn z.B. nur zwei Nachrichten, die miteinander verbunden werden können oder z.B. Eine thread_id-Spalte, die alle Nachrichten im selben "thread" verlinkt, aber mit der parent_id-Datei wird ständig verschoben. Ich habe Probleme, es herauszufinden.

+0

Welche Oracle-Version verwenden Sie? –

+0

12c Standardausgabe – taurijuhkam

Antwort

5

In Oracle ist dies leicht 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; 

Dies geht den Baum von oben nach unten durchgeführt unter Verwendung.

Wenn Sie den Baum aus einer einzigen Nachricht an die Wurzel gehen wollen, die start with ändern und den connect by Teil:

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

Tippfehler? Ich denke du meinst: 'connect by price MESSAGE_id = parent_id;' ?? – Ditto

+0

@ Ditto: ja, danke. –

+1

Das scheint meistens der Trick zu sein, aber: Was ist, wenn ich die ID der Wurzel der Konversation nicht kenne? Die meiste Zeit arbeitet es tatsächlich rückwärts -> Benutzer wählt eine Nachricht aus und ich muss vorherige Nachrichten anzeigen. Ich kenne also den letzten oder einen der mittleren message_id's und ich muss rückwärts gehen. Wenn ich Anfang mit der aktuellen Nachrichten-ID ersetze, erhalte ich nicht die vorherigen Nachrichten, sondern die nach der aktuellen Nachricht. E, g Ich weiß message_id 100 ist bar, wie komme ich zu mnessage_id 97, baz – taurijuhkam

1

den gesamten Nachrichtenkontext aus einem einzigen message_id Basis zu erhalten, können Sie verwenden zwei hierarchische Abfragen. Man geht den Nachrichtenbaum von der aktuellen Nachricht down zur Wurzel, während die zweite up von der Wurzel zu den Blättern zurückgeht. die aktuelle message_id Unter der Annahme, 100 (obwohl Werte von 101 oder 97 würde das gleiche Ergebnis haben), die folgende Abfrage alle zugehörigen Nachrichten zurückgibt (alle außer ‚Left out‘):

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; 

In der down Abfrage I‘ Es wurde darauf beschränkt, nur den Stammnachrichtenknoten (connect_by_isleaf) zurückzugeben, so dass start_id die Stammnachricht ist und die aktuelle message_id als curr_id zur Referenz in der Abfrage up enthält, wo ich eine Spalte eingefügt habe, um die aktuelle Nachricht mit einem Sternchen zu markieren .