Frage

Ich habe eine ähnliche Tabelle wie diese:

CREATE TABLE example (
  id integer primary key,
  name char(200),
  parentid integer,
  value integer);

Ich kann das Feld „Parentid“ verwenden, um Daten in einer Baumstruktur anzuordnen.

Hier ist der Teil, den ich nicht hinbekomme.Ist es bei gegebener Parent-ID möglich, eine SQL-Anweisung zu schreiben, um alle Wertfelder unter dieser Parent-ID zu addieren und den Zweig des Baums nach unten zu rekursieren?

AKTUALISIEREN: Ich verwende posgreSQL, daher stehen mir die schicken MS-SQL-Funktionen nicht zur Verfügung.Auf jeden Fall möchte ich, dass dies als generische SQL-Frage behandelt wird.

Übrigens bin ich sehr beeindruckt, dass ich innerhalb von 15 Minuten nach dem Stellen der Frage 6 Antworten erhalten habe!Los, Stapelüberlauf!

War es hilfreich?

Lösung

Es gibt verschiedene Möglichkeiten, in PostgreSQL das zu tun, was Sie brauchen.

Etwas wie das:

create or replace function example_subtree (integer)
returns setof example as
'declare results record;
         child record;
 begin
  select into results * from example where parent_id = $1;
  if found then
    return next results;
    for child in select id from example
                  where parent_id = $1
      loop
        for temp in select * from example_subtree(child.id)
        loop
          return next temp;
        end loop;
      end loop;
  end if;
  return null;
end;' language 'plpgsql';

select sum(value) as value_sum
  from example_subtree(1234);

Andere Tipps

Hier ist ein Beispielskript mit einem allgemeinen Tabellenausdruck:

with recursive sumthis(id, val) as (
    select id, value
    from example
    where id = :selectedid
    union all
    select C.id, C.value
    from sumthis P
    inner join example C on P.id = C.parentid
)
select sum(val) from sumthis

Das obige Skript erstellt eine „virtuelle“ Tabelle namens sumthis das hat Spalten id Und val.Es ist definiert als das Ergebnis zweier zusammengeführter Auswahlen union all.

Erste select erhält die Wurzel (where id = :selectedid).

Zweite select Folgt den untergeordneten Elementen der vorherigen Ergebnisse iterativ, bis nichts mehr zurückgegeben werden kann.

Das Endergebnis kann dann wie eine normale Tabelle verarbeitet werden.In diesem Fall wird die Val-Spalte summiert.

Seit Version 8.4 hat PostgreSQL Unterstützung für rekursive Abfragen für gängige Tabellenausdrücke unter Verwendung des SQL-Standards WITH Syntax.

Wenn Sie eine tragbare Lösung suchen, die auf jedem ANSI funktioniert SQL-92 RDBMS verwenden, müssen Sie Ihrer Tabelle eine neue Spalte hinzufügen.

Joe Celko ist der ursprüngliche Autor des Verschachtelte Mengen Ansatz zum Speichern von Hierarchien in SQL.Sie können googeln Hierarchie der „verschachtelten Mengen“. um mehr über die Hintergründe zu erfahren.

Oder Sie können parentid einfach in umbenennen links und füge ein hinzu Richtig.

Hier ist mein Versuch, Nested Sets zusammenzufassen, was völlig unzureichend sein wird, weil ich kein Joe Celko bin:SQL ist eine satzbasierte Sprache und das Adjazenzmodell (das die übergeordnete ID speichert) ist KEINE satzbasierte Darstellung einer Hierarchie.Daher gibt es keine rein satzbasierte Methode zur Abfrage eines Adjazenzschemas.

Jedoch, Die meisten großen Plattformen haben in den letzten Jahren Erweiterungen eingeführt, um genau dieses Problem zu lösen.Wenn also jemand mit einer Postgres-spezifischen Lösung antwortet, verwenden Sie diese unbedingt.

Eine Standardmethode zum Erstellen einer rekursiven Abfrage SQL sind rekursiv CTE. PostgreSQL unterstützt sie seitdem 8.4.

In früheren Versionen können Sie eine rekursive Mengenrückgabefunktion schreiben:

CREATE FUNCTION fn_hierarchy (parent INT)
RETURNS SETOF example
AS
$$
        SELECT  example
        FROM    example
        WHERE   id = $1
        UNION ALL
        SELECT  fn_hierarchy(id)
        FROM    example
        WHERE   parentid = $1
$$
LANGUAGE 'sql';

SELECT  *
FROM    fn_hierarchy(1)

Siehe diesen Artikel:

Wenn Sie SQL Server 2005 verwenden, gibt es eine wirklich coole Möglichkeit, dies mithilfe allgemeiner Tabellenausdrücke zu tun.

Es nimmt Ihnen die ganze Arbeit ab, die mit der Erstellung einer temporären Tabelle verbunden ist, und ermöglicht es Ihnen im Grunde, alles mit nur einem WITH und einer UNION zu erledigen.

Hier ist ein gutes Tutorial:

http://searchwindevelopment.techtarget.com/tip/0,289483,sid8_gci1278207,00.html

benutze einen allgemeiner Tabellenausdruck.

Möglicherweise möchten Sie angeben, dass es sich nur um SQL Server 2005 oder höher handelt. Dale Ragan

Hier ist ein Artikel bei Rekursion durch SqlTeam ohne gemeinsame Tabellenausdrücke.

Der folgende Code wird kompiliert und auf OK getestet.

create or replace function subtree (bigint)
returns setof example as $$
declare
    results record;
    entry   record;
    recs    record;
begin
    select into results * from example where parent = $1;
    if found then
        for entry in select child from example where parent = $1 and child  parent loop
            for recs in select * from subtree(entry.child) loop
                return next recs;
            end loop;
        end loop;
    end if;
    return next results;
end;
$$ language 'plpgsql';

Die Bedingung „Kind <> Eltern“ ist in meinem Fall erforderlich, da Knoten auf sich selbst zeigen.

Viel Spaß :)

Oracle hat „START WITH“ und „CONNECT BY“

select 
    lpad(' ',2*(level-1)) || to_char(child) s

from 
    test_connect_by 

start with parent is null
connect by prior child = parent;

http://www.adp-gmbh.ch/ora/sql/connect_by.html

Nur kurz nebenbei, obwohl die Frage sehr gut beantwortet wurde, sollte angemerkt werden, dass wir dies wie folgt behandeln:

generische SQL-Frage

dann ist die SQL-Implementierung ziemlich einfach, da SQL'99 eine lineare Rekursion in der Spezifikation zulässt (obwohl ich glaube, dass kein RDBMS den Standard vollständig implementiert). WITH RECURSIVE Stellungnahme.Aus theoretischer Sicht können wir dies also jetzt tun.

Keines der Beispiele hat für mich einwandfrei funktioniert, also habe ich es wie folgt behoben:

declare
    results record;
    entry   record;
    recs    record;
begin
    for results in select * from project where pid = $1 loop
        return next results;
        for recs in select * from project_subtree(results.id) loop
            return next recs;
        end loop;
    end loop;
    return;
end;

ist das SQL Server?Könnten Sie nicht eine gespeicherte TSQL-Prozedur schreiben, die die Ergebnisse durchläuft und zusammenführt?

Ich bin jedoch auch daran interessiert, ob es eine reine SQL-Möglichkeit gibt, dies zu tun.Nach den Teilen, an die ich mich aus meinem Kurs über geografische Datenbanken erinnere, sollte es welche geben.

Ich denke, dass es in SQL 2008 einfacher ist Hierarchie-ID

Wenn Sie beliebige Diagramme und nicht nur Hierarchien speichern müssen, können Sie Postgres beiseite schieben und eine Diagrammdatenbank wie z. B. ausprobieren AllegroGraph:

Alles in der Diagrammdatenbank wird als Tripel gespeichert (Quellknoten, Kante, Zielknoten) und bietet Ihnen erstklassige Unterstützung für die Bearbeitung der Diagrammstruktur und deren Abfrage mithilfe einer SQL-ähnlichen Sprache.

Es lässt sich nicht gut in etwas wie Hibernate oder Django ORM integrieren, aber wenn Sie es mit Diagrammstrukturen (nicht nur mit Hierarchien, wie sie das Nested-Set-Modell bietet) ernst meinen, probieren Sie es aus.

Ich glaube auch, dass Oracle in seinen neuesten Produkten endlich Unterstützung für echte Graphen hinzugefügt hat, aber ich bin erstaunt, dass es so lange gedauert hat, dass viele Probleme von diesem Modell profitieren könnten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top