Rekursive Funktionen

Mit Hil­fe rekur­si­ver Views kön­nen rekrusi­ve Funk­tio­nen, wie die Fakul­täts-Funk­ti­on oder deri Fibo­nac­ci-Funk­ti­on, defi­niert wer­den. Ein Daten­mo­dell, d.h. Tabel­len, in denen ande­re Wer­te gepei­chert wer­den, ist dafür nicht not­wen­dig. (Aller­dings ist es aus Per­formanz­grün­den evtl. sinn­voll, die Ergeb­nis­se die­ser Views dau­er­haft in Mate­ria­li­zed View oder nor­ma­len Tabel­len zu spei­chern, da die Berech­nung von Wer­ten wie 30000! oder fibonacci(100000) rela­tiv zeit­auf­wän­dig ist. Die resul­tie­ren­den Zah­len haben ziem­lich vie­le Stel­len.)

ACHTUNG
In der fol­gen­den Tabel­le sind Anwei­sun­gen ent­hal­ten, um Fakul­täts­wer­te in einer Tabel­le oder Mate­ria­li­zed View zu spei­chern. Füh­ren Sie die­se Anwei­se­un­gen bit­te nicht aus, da jede die­ser Tabel­len 500 MB Platz ein­nimmt. And­ren­falls läuft das Back­up-Sys­tem des Prak­ti­kums­ser­vers ziem­lich sicher kurz dar­auf über.

recursion.sql(Rekur­si­ve Anfra­gen)

Vereinfachte Ahnen-Datenbank

Um die Ver­ar­bei­tung von rekur­si­ven Anfra­gen demons­trie­ren zu kön­nen, wür­de ein ziem­lich ein­fa­ches Daten­mo­dell gewählt:

eltern: kind VARCHAR, elter VARCHAR {PK: kind, elter}

Anmer­kung
Eigent­lich han­delt es sich dabei um eine Bezie­hungs­ta­bel­le zwi­schen Per­so­nen. Aller­dings wer­den aus Ver­ein­fa­chungs­grün­den die Per­so­nen nicht sepa­rat gespei­chert, son­dern an Stel­le von For­eign-Key-Wer­ten die Namen der Per­so­nen gleich direkt in die Bezie­hungs­ta­bel­le ein­ge­tra­gen. Dies ist kei­ne sau­be­re Art der Model­lie­rung. Im dar­auf fol­gen­den Bei­spiel sehen Sie, wie man es bes­ser machen kann und soll­te. In die­sem Bei­spiel geht es nur um die prin­zi­pi­el­le Idee.

genealogy_simple.sql(CREA­TE-TABLE-/IN­SERT-Befeh­le und Anfra­gen)

Ahnen-Datenbank

Und jetzt das­sel­be noch ein­mal mit einem bes­se­ren Modell:

e_person:    p_id, p_name, p_geschlecht, m_id*, v_id*  {PK: p_id}
                                {FK: m_id -> person: p_id}         
                                {FK: v_id -> person: p_id}
generation: g_id,                                      {PK: g_id}  
            g_bezeichnung, g_bezeichnung_frau, g_bezeichnung_mann

Von einer Per­son kön­nen Mut­ter und Vater bekannt sein. Das es sich bei die­sen auch um Per­so­nen han­delt, wird per Fremd­schlüs­sel auf sie ver­wie­sen:

  • m_id: Mut­ter
  • v_id: Vater

Beach­ten Sie, das damit eine rekur­si­ve Daten­struk­tur defi­niert wird. Die Attri­bu­te m_id und v_id müs­sen null­ab­le sein, da sonst uned­n­lcih vie­le Daten ein­ge­pflegt wer­den müss­te. Spä­tes­tens bei Adam und Eva ist Schluss (ver­mut­lich schon viel frü­her, da es nur weni­ge Mesnschen geben dürf­te, die die Namen sämt­li­cher Vor­fah­ren ken­nen. 🙂 ).

Mit Hil­fe der Tabel­le e_person kön­nen diver­se Views gebil­det wer­den:

  • person: Wie e_person, nur ist jeweils noch der Namen der Mut­ter (m_​name) und des Vaters (v_name) als Attri­but ent­hal­ten:
    person (p_id, p_name, p_geschlecht, m_id, m_name, v_id, v_name)
  • eltern: Ana­log zur Tabel­le aus dem obi­gen Bei­spiel, nur mit mehr Attri­bu­ten:
    eltern (p_id, p_name, p_geschlecht, e_id, e_name, e_geschlecht)
    (p_... bezeich­net die Per­son selbst, e_... ein Eltern­teil)
  • vorfahren_1: Die rekur­si­ve Ver­all­ge­mei­ne­rung der Eltern­ta­bel­le aus dem obi­gen Bei­spiel:
    vorfahren_1 (p_id, v_id)
  • vorfahren_2: Die rekur­si­ve Ver­all­ge­mei­ne­rung der Eltern­ta­bel­le aus die­sem Bei­spiel () :
    vorfahren_2 (p_id, p_name, p_geschlecht, v_id, v_name, v_geschlecht,
    g_id, g_bezeichnung, g_bezeichnung_geschlecht
    )

    Die­se View ent­hält auch noch für jede Gene­ra­ti­on die Gene­ra­ti­on aus Sicht der jewei­li­gen Per­son. Hier kommt die Enum-Tabel­le generation zum Ein­satz.

genealogy_create.sql(CREATE-TABLE- und INSERT-Befeh­le)
genealogy_query.sql(Rekur­si­ve Anfra­gen)
genealogy_query_list_aggregation.sql(Lis­ten-Aggre­ga­ti­on über rekrusi­ve Views)