SQL - Durchsuchen einer Baumstruktur
Hallo Forum,
mal wiede eine Frage bei der ich nicht so recht weiter weiss.
Folgendes Problem in einer SQL Datenbank:
Die Daten liegen folgendermasen in der Bank:
Felder:
ID
VaterID
Name
Anzahl
1, NULL, AAAA, NULL
2, 1, BBB, NULL
3, 2, hziui, 887
4, 2, htzs, 776
5, 1, hdtds, NULL
6, 5, jkhasodu, 987958
7, 5, kjoiusdad, 98798729344
Die Daten Daten können also sowohl Knoten als auch Endpunkt sein.
Ich denke ich muss hier mit einer while Schleife arbeiten - die Frage ist wie könnte diese Ausehen?
Danke und Gruß Markus
mal wiede eine Frage bei der ich nicht so recht weiter weiss.
Folgendes Problem in einer SQL Datenbank:
Die Daten liegen folgendermasen in der Bank:
Felder:
ID
VaterID
Name
Anzahl
1, NULL, AAAA, NULL
2, 1, BBB, NULL
3, 2, hziui, 887
4, 2, htzs, 776
5, 1, hdtds, NULL
6, 5, jkhasodu, 987958
7, 5, kjoiusdad, 98798729344
Die Daten Daten können also sowohl Knoten als auch Endpunkt sein.
Ich denke ich muss hier mit einer while Schleife arbeiten - die Frage ist wie könnte diese Ausehen?
Danke und Gruß Markus
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 148782
Url: https://administrator.de/forum/sql-durchsuchen-einer-baumstruktur-148782.html
Ausgedruckt am: 23.12.2024 um 08:12 Uhr
31 Kommentare
Neuester Kommentar
Hi,
falls das Ziel darin besteht, die Struktur hierarchisch auzugliedern, könnte folgendes Hilfreich sein:
SELECT ID, VaterID
FROM <tabelle>
CONNECT BY PRIOR ID = VaterID
START WITH ID = 1
(nicht getestet aber aus einem Beispiel übernommen und umgeschrieben).
Interessant zum Thema CONNECT BY PRIOR / Treewalking mit SQL ist auch der Link:
http://www.akadia.com/services/ora_treewalking_with_sql.html
Hoffe das Hilft weiter.
Grüße Netzfetzer
falls das Ziel darin besteht, die Struktur hierarchisch auzugliedern, könnte folgendes Hilfreich sein:
SELECT ID, VaterID
FROM <tabelle>
CONNECT BY PRIOR ID = VaterID
START WITH ID = 1
(nicht getestet aber aus einem Beispiel übernommen und umgeschrieben).
Interessant zum Thema CONNECT BY PRIOR / Treewalking mit SQL ist auch der Link:
http://www.akadia.com/services/ora_treewalking_with_sql.html
Hoffe das Hilft weiter.
Grüße Netzfetzer
Hallo Markus,
wenn ich dich richtig verstanden habe willst du die Artikel mit der höchsten Anzahl herausfinden.
Es kann sein das diese Artikel Kinder eines Vaterartikels sind (Mitglied einer Artikelliste).
Ich habe allerdings nicht verstanden ob du nur die reinen Artikel haben willst oder auch die Artikel die Mitglied einer Artikelliste sind.
Schick doch mal jeweils einen Datensatz für jedes Beispiel damit man den Aufbau sehen kann.
it-frosch
wenn ich dich richtig verstanden habe willst du die Artikel mit der höchsten Anzahl herausfinden.
Es kann sein das diese Artikel Kinder eines Vaterartikels sind (Mitglied einer Artikelliste).
Ich habe allerdings nicht verstanden ob du nur die reinen Artikel haben willst oder auch die Artikel die Mitglied einer Artikelliste sind.
Schick doch mal jeweils einen Datensatz für jedes Beispiel damit man den Aufbau sehen kann.
it-frosch
Hallo Markus,
ich muss noch mal drauf nachfragen weil es immer noch nicht klar ist.
Was willst du konkret auswerten?
Und wie sehen Beispieldatensätze (id ohne Sohn mit Tagen, Id mit mehreren Söhen und mit Tagen, Daten die du nicht auswerten willst) aus?
Willst du IDs mit oder/und ohne Söhnen auswerten?
Wenn du IDs mit Söhnen auswerten willst, soll sich Anzahl der Tage auf die "Vater" ID beziehen oder auf den letzten Sohn?
Ich glaube du musst in deinem Kopf dir das ganze erst einmal klar machen.
Nimm dir ein Blatt und schreib dir dir Strukturen auf. Wenn du es dann hast, stelle die Antworten hier rein.
grüße vom it-frosch
ich muss noch mal drauf nachfragen weil es immer noch nicht klar ist.
Was willst du konkret auswerten?
Und wie sehen Beispieldatensätze (id ohne Sohn mit Tagen, Id mit mehreren Söhen und mit Tagen, Daten die du nicht auswerten willst) aus?
Willst du IDs mit oder/und ohne Söhnen auswerten?
Wenn du IDs mit Söhnen auswerten willst, soll sich Anzahl der Tage auf die "Vater" ID beziehen oder auf den letzten Sohn?
Ich glaube du musst in deinem Kopf dir das ganze erst einmal klar machen.
Nimm dir ein Blatt und schreib dir dir Strukturen auf. Wenn du es dann hast, stelle die Antworten hier rein.
grüße vom it-frosch
Hallo Markus,
unter der Voraussetzung das ein Endpunkt ein Artikel ist der in der Vater-Sohn-Tabelle nur als Ressource auftaucht würde ich sagen.
select tabelle2.artikelnummer,max(tabelle2.wiederbeschaffungszeit) from tabelle2
where
tabelle2.artikelnr in (select tabelle1.ressourcennummer from tabelle1)
and
tabelle2.artikelnr not in (select tabelle1.artikelnr from tabelle1)
group by tabelle2.artikelnummer
order by 2 desc;
Damit erhälst du eine Liste aus Artikelnummer und höchster Wiederbeschaffungszeit pro Artikel sortiert nach der größten Wiederbeschaffungszeit.
grüße vom it-frosch
PS: In der Hoffnung dich nun richtig verstanden zu haben.
unter der Voraussetzung das ein Endpunkt ein Artikel ist der in der Vater-Sohn-Tabelle nur als Ressource auftaucht würde ich sagen.
select tabelle2.artikelnummer,max(tabelle2.wiederbeschaffungszeit) from tabelle2
where
tabelle2.artikelnr in (select tabelle1.ressourcennummer from tabelle1)
and
tabelle2.artikelnr not in (select tabelle1.artikelnr from tabelle1)
group by tabelle2.artikelnummer
order by 2 desc;
Damit erhälst du eine Liste aus Artikelnummer und höchster Wiederbeschaffungszeit pro Artikel sortiert nach der größten Wiederbeschaffungszeit.
grüße vom it-frosch
PS: In der Hoffnung dich nun richtig verstanden zu haben.
ich glaube ich habe dein Problem verstanden.
Du hast eine Artikel-Stücklisten-Struktur und willst die maximale Wiederbeschaffungszeit/Durchlaufzeit erhalten. Dabei wird in Tabelle A die Zusammensetzung (Artikel / Komponente bzw. Ressource) und in Tabelle B die WBZ/DLZ der einzelnen Ressourcen festgelegt.
Dann hätte ich als Lösungsvorschlag sowas in der Art (nicht getestet):
1. Struktur des Artikels
SELECT TAB_A.Artikelnummer as ART_NR ,
TAB_A.Ressourcenummer as RES_NR,
max(TAB_B.Wiederbeschaffungszeit) as WBZ
FROM TAB_A left join TAB_B on TAB_A.Ressourcennummer = TAB_B.Artikelnummer
CONNECT BY PRIOR TAB_A.Artikelnummer = TAB_A.Ressourcenummer
GROUP BY ART_NR, RES_NR
ich weiß nicht genau wie bei dir dann das Ergebnis aussieht, aber du könntest sicher dann eine Abfrage um diese herum "bauen", wo du dir die WBZ pro "Kopfartikel" summieren lässt...
Gruß Netzfetzer
Du hast eine Artikel-Stücklisten-Struktur und willst die maximale Wiederbeschaffungszeit/Durchlaufzeit erhalten. Dabei wird in Tabelle A die Zusammensetzung (Artikel / Komponente bzw. Ressource) und in Tabelle B die WBZ/DLZ der einzelnen Ressourcen festgelegt.
Dann hätte ich als Lösungsvorschlag sowas in der Art (nicht getestet):
1. Struktur des Artikels
SELECT TAB_A.Artikelnummer as ART_NR ,
TAB_A.Ressourcenummer as RES_NR,
max(TAB_B.Wiederbeschaffungszeit) as WBZ
FROM TAB_A left join TAB_B on TAB_A.Ressourcennummer = TAB_B.Artikelnummer
CONNECT BY PRIOR TAB_A.Artikelnummer = TAB_A.Ressourcenummer
GROUP BY ART_NR, RES_NR
ich weiß nicht genau wie bei dir dann das Ergebnis aussieht, aber du könntest sicher dann eine Abfrage um diese herum "bauen", wo du dir die WBZ pro "Kopfartikel" summieren lässt...
Gruß Netzfetzer
Naja das in Tab_B Einträge vorkommen, die mit Tab_A nichts zu tun haben, ist für die Abfrage ja eigentlich egal, da sie die Artikel und Ressourcen aus der Tab_A nimmt und nur die WBZ's aus Tab_B zuordnet...
Dein Beispiel würde doch so aussehen
81400002
-> 82150003 -> 42d WBZ
-> 82150018 -> 58d WBZ
Was willst du als Ergebnis erhalten?
81400002 - 58???
Dein Beispiel würde doch so aussehen
81400002
-> 82150003 -> 42d WBZ
-> 82150018 -> 58d WBZ
Was willst du als Ergebnis erhalten?
81400002 - 58???
Du willst also eine Routine, der du 81400002 mitgibst...
wie soll dann das Ergebnis aussehen??? Weil aus dem oben genannten Beispiel würde ich folgendes Schlussfolgern:
Artikel = 81400002
-> Ressource = 82150003 -> WBZ = 42
-> Ressource = 82150018 -> WBZ = 58
Ergebnis:
max(WBZ) = 58
ist das richtig oder nicht???
--damit solltest du das ergebnis erhalten:
select max(tab_b.wbz)
from tab_b, tab_a
where tab_b.artikelnummer in
(select ressource
from tab_a
where artikelnummer = :artikelnummer -- z.B. 81400002)
wie soll dann das Ergebnis aussehen??? Weil aus dem oben genannten Beispiel würde ich folgendes Schlussfolgern:
Artikel = 81400002
-> Ressource = 82150003 -> WBZ = 42
-> Ressource = 82150018 -> WBZ = 58
Ergebnis:
max(WBZ) = 58
ist das richtig oder nicht???
--damit solltest du das ergebnis erhalten:
select max(tab_b.wbz)
from tab_b, tab_a
where tab_b.artikelnummer in
(select ressource
from tab_a
where artikelnummer = :artikelnummer -- z.B. 81400002)
ok so langsam verstehe ich das Problem =D
ich bin dennoch der Meinung, das dir hier ein Treewalker am besten hilft...
SELECT ressource
FROM tab_a
CONNECT BY PRIOR artikelnummer = ressource
START WITH artikelnummer = 81400002
hiermit (oder so ähnlich) müsstest du die ressourcen auslesen können, welche ganz unten in deiner hierarchie stehen. mit einem select um diesen select könntest du dir dann aus tabelle B noch die WBZ's dazu lesen.
Du kannst ja auch mal versuchen, in das select die wbz mit einzubinden. evtl. kannst du dir dann mit einem weiteren select die max(WBZ) auslesen lassen...
ich bin dennoch der Meinung, das dir hier ein Treewalker am besten hilft...
SELECT ressource
FROM tab_a
CONNECT BY PRIOR artikelnummer = ressource
START WITH artikelnummer = 81400002
hiermit (oder so ähnlich) müsstest du die ressourcen auslesen können, welche ganz unten in deiner hierarchie stehen. mit einem select um diesen select könntest du dir dann aus tabelle B noch die WBZ's dazu lesen.
Du kannst ja auch mal versuchen, in das select die wbz mit einzubinden. evtl. kannst du dir dann mit einem weiteren select die max(WBZ) auslesen lassen...
hmm ok das ist ein gutes argument...
kann dir folgendes anbieten:
http://phpperformance.de/nested-sets-hierarchische-strukturen-und-baeum ...
http://forums.mysql.com/read.php?98,38047,38089#msg-38089
wenn das nicht hilft, dann müssen wir uns einen neuen ansatz ausdenken...
kann dir folgendes anbieten:
http://phpperformance.de/nested-sets-hierarchische-strukturen-und-baeum ...
http://forums.mysql.com/read.php?98,38047,38089#msg-38089
wenn das nicht hilft, dann müssen wir uns einen neuen ansatz ausdenken...
Evtl. hilft da sowas in der Art:
Quelle: http://www.ms-office-forum.net/forum/showthread.php?t=267959
innerhalb der Schleife muss man dann eine weitere Schleife durchgehen, da es ja mehr als einen Sohn geben kann. ist man ganz am ende, müsste man sich den letzten wert in ein array schreiben.
evtl. kannst du dir einen view oder eine temp. tabelle aufbauen um das ganze zu vereinfachen?!
eine weitere alternative wäre evtl., mittels PL/SQL eine Funktion zu schreiben, die sich selbst wieder aufruft und checkt, ob söhne vorhanden sind...wenn nein dann weißt du, das du am ende bist, und wenn ja dann rufst du die selbe funktion wieder auf um nach söhnen zu schauen.
Gruß Netzfetzer
Quelle: http://www.ms-office-forum.net/forum/showthread.php?t=267959
innerhalb der Schleife muss man dann eine weitere Schleife durchgehen, da es ja mehr als einen Sohn geben kann. ist man ganz am ende, müsste man sich den letzten wert in ein array schreiben.
evtl. kannst du dir einen view oder eine temp. tabelle aufbauen um das ganze zu vereinfachen?!
eine weitere alternative wäre evtl., mittels PL/SQL eine Funktion zu schreiben, die sich selbst wieder aufruft und checkt, ob söhne vorhanden sind...wenn nein dann weißt du, das du am ende bist, und wenn ja dann rufst du die selbe funktion wieder auf um nach söhnen zu schauen.
Gruß Netzfetzer
Öhmm, Netzfetzer,
Aber ansonsten natürlich... die Rekursivität lässt sich natürlich auch mit einer Stored Procedure nachbilden..
Grüße
Biber
Zitat von @Netzfetzer:
eine weitere alternative wäre evtl., mittels PL/SQL eine Funktion zu schreiben, die sich selbst wieder aufruft und checkt, ob
söhne vorhanden sind...wenn nein dann weißt du, das du am ende bist, und wenn ja dann rufst du die selbe funktion
wieder auf um nach söhnen zu schauen.
Sagen wir so... wenn Arafats Datenbankblech PL/SQL verstehen würde, dann würde es auch "CONNECT BY PRIOR" verstehen.eine weitere alternative wäre evtl., mittels PL/SQL eine Funktion zu schreiben, die sich selbst wieder aufruft und checkt, ob
söhne vorhanden sind...wenn nein dann weißt du, das du am ende bist, und wenn ja dann rufst du die selbe funktion
wieder auf um nach söhnen zu schauen.
Aber ansonsten natürlich... die Rekursivität lässt sich natürlich auch mit einer Stored Procedure nachbilden..
Grüße
Biber
Hi,
wie wäre es denn mit einer rekursiven schleife?
also so in der art (keine SQL-Syntax - nur als Denkansatz gedacht!):
function FINDSONS (artnr in varchar2)
declare
artnr as varchar2;
begin
while ( (select count(*) from tab_a where artikelnummer = artnr) > 0 ) begin
--noch nicht am ende
select artikelnummer from tab_a where artikelnummer = artnr;
-- die ergebnismenge müsste man in einer schleife durchgehen und hier wieder die Funktion FINDSONS aufrufen (mit übergebener neuer Artikelnummer)
end
--wenn count(*) = 0 dann bist du in der struktur am ende, heißt du hast deinen untersten knoten und kannst mit einem select die WBZ für die Artikelnummer abfragen und diese dir in ein array oder eine tabelle o.ä. schreiben...
end;
also wie gesagt, ist jetzt nur so nen denkansatz...ich habe auch vorerst keinen wert auf syntax o.ä. gelegt...
Gruß Netzfetzer
wie wäre es denn mit einer rekursiven schleife?
also so in der art (keine SQL-Syntax - nur als Denkansatz gedacht!):
function FINDSONS (artnr in varchar2)
declare
artnr as varchar2;
begin
while ( (select count(*) from tab_a where artikelnummer = artnr) > 0 ) begin
--noch nicht am ende
select artikelnummer from tab_a where artikelnummer = artnr;
-- die ergebnismenge müsste man in einer schleife durchgehen und hier wieder die Funktion FINDSONS aufrufen (mit übergebener neuer Artikelnummer)
end
--wenn count(*) = 0 dann bist du in der struktur am ende, heißt du hast deinen untersten knoten und kannst mit einem select die WBZ für die Artikelnummer abfragen und diese dir in ein array oder eine tabelle o.ä. schreiben...
end;
also wie gesagt, ist jetzt nur so nen denkansatz...ich habe auch vorerst keinen wert auf syntax o.ä. gelegt...
Gruß Netzfetzer
Hallo Markus,
Prinzipiell hast du aber recht.
grüße vom it-frosch
da habe ich das Problem, dass der Baum in einem anderen Programm (Sage) generiert wird face-sad ... Hier möchte ich nicht in deren Tabelle "rumpfuschen".
Mmh, verstehe ich obwohl ein Trigger auf einer Programm-Tabelle der in einer nicht zum Programm gehörenden Tabelle Aktionen auslöst für mich noch nicht unbedingt "rumpfuschen" ist. Prinzipiell hast du aber recht.
grüße vom it-frosch