it-swarm.com.de

Alle Nachkommen eines Elternteils abrufen

Ich habe eine Tabelle mit zwei Spalten, Parent und Child.

Ich muss die Liste aller Nachkommen abrufen, die den übergeordneten Datensätzen zugeordnet sind.

Source Table
+----+-----------+
| Parent | Child |
+----+-----------+
|  a     |     b |
|  b     |     c |
|  c     |     d |
|  d     |     e |
|  e     |     f |
|  f     |     x |
+----+-----------+

Expected Result:
+----+-----------+
| Parent | Child |
+----+-----------+
|  a     |     b |  // As b is the child of a, all the descendants of b 
|  a     |     c |  // are also descendants of a. 
|  a     |     d |
|  a     |     e |
|  a     |     f |
|  a     |     x |
|  b     |     c |  // As c is the child of b, all the descendants of c 
|  b     |     d |  // are also descendants of b.
|  b     |     e |
|  b     |     f |
|  b     |     x |
|  c     |     d |
|  c     |     e |
|  c     |     f |
|  c     |     x |
|  d     |     e |
|  d     |     f |
|  d     |     x |
|  e     |     f |
|  e     |     x |
|  f     |     x |
+----+-----------+

Irgendwelche Ideen, wie man alle Nachkommen-Aufzeichnungen eines Elternteils erhält? Ich habe versucht, mich mit T1.Child = T2.Parent Selbst zu verbinden, aber die Logik hat nicht funktioniert.

Ich verwende Teiid VDB, die die Klausel Recursive WITH Nicht unterstützt.

6
lourdh

Sie benötigen einen rekursiven CTE (Common Table Expression):

with    -- recursive
        -- some DBMS (e.g. Postgres) require the Word "recursive"
        -- some others (Oracle, SQL-Server) require omitting the "recursive"
        -- and some (e.g. SQLite) don't bother, i.e. they accept both
descendants
  (parent, descendant, lvl) 
as
  ( select parent, child, 1
    from source
  union all
    select d.parent, s.child, d.lvl + 1
    from descendants  d
      join source  s
        on d.descendant = s.parent
  ) 
select *
from descendants 
order by parent, lvl, descendant ;

Siehe SQLfiddle. Das level, das ich hinzugefügt habe, wird nicht benötigt. Es gibt Ihnen die "Distanz" zwischen dem Elternteil und dem Nachkommen (1 ist Kind, 2 ist Enkel usw.).

Link für die zugehörige Teiid-Dokumentation zu: (rekursiven) CTEs .

PS: Für Oracle:

  • LEVEL ist ein eingeschränktes Schlüsselwort
16
ypercubeᵀᴹ

Wenn Sie mit dieser Datenstruktur nicht weiterkommen, müssen Sie einen rekursiven CTE verwenden: http://www.postgresql.org/docs/8.4/static/queries-with.html
Wenn die Dokumentation nicht klar ist, kann eine schnelle Suche hilfreich sein: Eine solche Baumdurchquerung ist die häufigste Verwendung für sie, sodass Sie viele Beispiele finden, wenn Sie nach "rekursivem allgemeinen Tabellenausdruck" suchen.

Es gibt Strukturen, die wesentlich effizientere Abfragen dieser Art ermöglichen, die jedoch zusätzliche Arbeit erfordern, um bei Aktualisierungen gewartet zu werden. Zwei gängige Optionen sind:

  1. Generieren des vollständigen Pfads zu einem Knoten (d. H./A/b/c) im Baum und Speichern dieses Pfads in einer indizierten Spalte. Um dies unter a nach allen zu suchen, können Sie das Prädikat LIKE '/a/% Verwenden, und für diejenigen unter b verwenden Sie LIKE '/a/b/%'. Für a und seine Nachkommen LIKE '/a%'. Dies ist für Einfügungen leicht zu pflegen, aber Sie müssen vorsichtig sein, um die Pfade zu aktualisieren (möglicherweise durch Auslöser), wenn sich etwas anderes Relevantes ändert: Wenn sich beispielsweise b bewegt, müssen Sie die gespeicherten Pfade von sich selbst und aktualisieren alle seine Nachkommen.

  2. Speichern eines Entfernungsdiagramms. Also für b speichern Sie b,b,0, b,a,1 Und für cc,c,0, c,b,1, c,a,2 in Ihrer Beziehungstabelle. Auch hier müssen Sie einige Arbeiten ausführen, um dies beizubehalten, wenn Knoten verschoben werden. Diese Option ermöglicht flexiblere Abfragen sowohl nach oben als auch nach unten im Baum. Wenn Sie SELECT * FROM relationship_graph WHERE distance=1 Haben, haben Sie Ihren ursprünglichen Baum.

Wenn Sie Zugriff auf eine Kopie haben (wenn nicht, empfehle ich, sie zu finden!), Scannen Sie das Kapitel Naive Bäume von SQL Anitpatterns. Dies deckt dies in ausreichend nützlichen Details ab und ist für weniger erfahrene Personen zugänglich.

Wenn Sie die Struktur nicht ändern können (da es sich um ein vorhandenes System handelt, über das Sie nur wenig Kontrolle haben) und keine rekursiven CTEs verwenden können, müssen Sie entweder:

  • Verwenden Sie eine gespeicherte Prozedur, um Knoten zu schleifen, bis Sie den Boden erreichen

  • Verwenden Sie etwas Böses und Ineffizientes mit vielen Verknüpfungen zur Beziehungstabelle, um die Knoten herauszuziehen. Dies ist auf die Tiefe beschränkt, die gesucht werden kann, und versucht immer, diese Tiefe zu suchen, auch wenn dies nicht erforderlich ist. Alle oben genannten Optionen können effektiv unendliche Tiefen scannen.

4
David Spillett

Teiid unterstützt einfach nicht, was Sie wollen.

Aus diesem Grund müssen Sie die VDB-Abstraktion unterbrechen und eine direkte Abfrage verwenden. Also Teiid aus der Gleichung herausrechnen. Welche Datenbank verwenden Sie unter der Haube?

0
Evan Carroll
create table pc ( parent varchar(10), child varchar(10) )

insert into pc values('a','b');
insert into pc values('a','c');
insert into pc values('b','e');
Insert into pc values('b','f');
insert into pc values('a','d');
insert into pc values('b','g');
insert into pc values('c','h');
insert into pc values('c','i');
insert into pc values('d','j');
insert into pc values('f','k');
insert into pc values('x','y');
insert into pc values('y','z');
insert into pc values('m','n');                       

DECLARE @parent varchar(10) = 'a';
WITH cte AS
(
  select null parent, @parent child, 0 as level
   union
  SELECT  a.parent, a.child , 1 as level
    FROM pc a
   WHERE a.parent = @parent
   UNION ALL
  SELECT a.parent, a.child , c.level +    1
    FROM pc a JOIN cte c ON a.parent = c.child
)
SELECT distinct parent, child , level
  FROM cte
 order by level, parent;

Dies gibt Ihnen alle Nachkommen und das Level.

Hoffe das hilft :)

0
Wohoooo