App installieren
How to install the app on iOS
Follow along with the video below to see how to install our site as a web app on your home screen.
Anmerkung: This feature may not be available in some browsers.
Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden.
Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
[SQL(Firebird)]: Rekursion und Baumstruktur Problem
- Ersteller Onkel Homie
- Erstellt am
Onkel Homie
Gesperrt
- Mitglied seit
- 26.03.2003
- Beiträge
- 15.842
- Renomée
- 390
- Standort
- Dortmund
- Aktuelle Projekte
- Spinhenge, SIMAP, QMC, POEM
- Lieblingsprojekt
- Spinhenge
- Meine Systeme
- C2D E8400 @3,8GHz
- BOINC-Statistiken
- Mein Laptop
- Lenovo TP Edge 13 NV122GE, Thinkpad R60 9461-DXG T5600 2GB
- Prozessor
- i7-3770k
- Mainboard
- Asrock Z77 Extreme 4
- Kühlung
- Thermalright Macho 120
- Speicher
- Kingston 1600 CL9 4x4096
- Grafikprozessor
- GTX 770 4096
- Display
- Dell U2713HM, Samsung 226BW
- HDD
- 1 x Samsung 840 Pro SSD, 2 x WD10EZEX 1 TB Raid 1
- Soundkarte
- Realtek onboard
- Gehäuse
- Nanoxia Deep Silence 2
- Netzteil
- beQuiet Straight Power E9 580W
- Betriebssystem
- Windows 8.1 Pro 64, Windows 7 Pro 64, Xubuntu 14.04
- Webbrowser
- Chrome
- Verschiedenes
- NAS: Synology DS214play; Kamera: Nikon D7100, Nexus 7 2013
Mahlzeit zusammen,
ich stehe gerade vor einem, für mich recht kniffligen, SQL Problem. Ich muss dazu sagen das ich bisher kaum was mit (Firebird)SQL gemacht habe und dort auch erst recht nichts mit Rekursionen, also bitte bei Anfängerfehlern nachsichtig sein
Vielleicht kann mir ja jemand helfen.
Nun aber zu meinem Problem:
Ausgangssituation:
2 Tabellen (T1, T2) sollen einen Baum ergeben dessen Struktur beispielsweise wie folgt aussieht:
Wichtig hierbei ist, dass ein Element aus T1 niemals das Child eines Elements aus T2 seien kann und es auch immer nur ein Element aus T1 im Baum als Root gibt.
Der problematische Teil stellt nun also die Anordnung der Elemente aus T2 dar.
Ich suche jetzt nach Möglichkeit eine rekursive SQL Anweisung um die korrekte Baumstruktur zu bekommen.
Einzelne Elemente sehen dabei wie folgt aus (E1 = Element aus T1, E2 = Element aus T2):
E1.ID
E2.ID, E2.RefUebergeordneteID (kann sowohl eine E1.ID als auch eine E2.ID sein), E2.RefUebergeordneteE1 (wurde bereits von mir hinzugefügt um etwas sortieren zu können)
Die anderen Attribute sind hier unwichtig, es geht nur um die Zuordnung der IDs bzw. eben der referenzierten IDs.
Das Problem ist, dass die ID jeweils GUI-IDs sind und keine aufeinander folgenden Indizes. Diese Struktur kann ich auch nicht groß umstellen. Insgesamt habe ich leider wenig Möglichkeiten die bereits vorhandene Struktur zu erweitern, ließe sich aber ggf. drüber diskutieren .
Mein Ansatz sieht nun bisher wie folgt aus:
Was dann leider zu einem durcheinander gewürfelten Ergebnis führt, da immer automatisch nach der kleinsten GUI-ID sortiert wird. Rekursionen schachteln geht scheinbar nicht in SQl (? meines Wissens sind nur From, Select und Where schachtelbar), daher komme ich nicht wirklich weiter. Denn das aktuell Ergebnis kriege ich auch viel einfacher mit einem:
An sich dachte ich eben die Rekursion würde meine Elemente nach folgendem Schema ausgeben:
- hole alle T2.RefUebergeordneteID mit ' <eine bestimmte GUI-ID>' als Tabelle rek
- hole alle Childs mit T2.RefUebergeordneteID = rek.ID wiederum als rek usw.
Nur leider wird dann halt sortiert
Wichtig ist auch noch das eine nested Struktur nicht in Frage kommt, da ständig Daten in die Tabelle 2 der Datenbank an beliebigen Stellen geschrieben, kopiert oder verschoben werden können und dann irgendwann der Aufwand zu groß wird die ganze Struktur immer neu durchzurechnen.
Falls es noch wichtig bzw. von Interesse ist: Es geht darum mittels eines C# Programms halt auf eine Firebird DB zuzugreifen und sich dabei viele Selectes zu ersparen, da aktuell die Situation so ist das bestimmte große vom Programm gestellte Anfragen alles lahmlegen Denn aktuell laufen da viele while-Schleifen ineinander die alle fröglich ihre Selects abfeuern, was einerseits lange dauert, andererseits halt den Speicher doch recht extrem belastet. Die Rede ist hier von locker 15.000 - 20.000 Anfragen die da beim Laden rausgehen. Das habe ich nicht gemacht, dass war netterweise schon so und lief bisher auch ganz gut...solange die Projekte an sich klein genug waren Daher ist das problem wohl bisher nie aufgefallen. Nur jetzt muss der Firebird-Server (die Software nicht die Hardware wo die DBs liegen) plötzlich um die 1,8GB bewältigen, was in der Version 2.1 auch nur unter Linux geht. Unter Windows steigt er einfach aus, der 2.5er Beta läuft durch aber es dauert immernoch sau lange die Daten zu laden so ca. 7-10min. Und in absehbarer Zeit ist die 6-7 fache Datenmange zu erwarten hehe.
Wäre klasse wenn jemand vielleicht einen Denkanstoß bzw. einen Lösungsansatz hätte
.
EDIT :
.
Einen Schritt weiter aber leider noch nicht ganz fertig sieht das Ganze nun so aus:
Das Ergebnis ist schon mal besser, aber der "counter" mit der stufe zählt noch nicht richtig hoch. An sich müsste er an eienr anderen Stelle sitzen, aber da kann ich ihn nirgends reinsetzen .
Im Prinzip würde mir ein group by RefUebergeordneteID vor dem Order by womöglich helfen, aber das kann wohl auf Grund der Rekursion nicht angewendet werden.
So langsam glaube ich das ich mein Problem mit reinem SQL nicht lösen kann und die Anwendung da selber doch mal sortieren muss. Dann muss ich zwar wieder ein paar Sachen nachladen, aber ich kann noch irgendwie versuchen die monströse Anzahl der Selects zu reduzieren.
Aber vielleicht hat hier ja doch noch wer die rettende Idee
ich stehe gerade vor einem, für mich recht kniffligen, SQL Problem. Ich muss dazu sagen das ich bisher kaum was mit (Firebird)SQL gemacht habe und dort auch erst recht nichts mit Rekursionen, also bitte bei Anfängerfehlern nachsichtig sein
Vielleicht kann mir ja jemand helfen.
Nun aber zu meinem Problem:
Ausgangssituation:
2 Tabellen (T1, T2) sollen einen Baum ergeben dessen Struktur beispielsweise wie folgt aussieht:
Code:
Element aus T1
|
| - Element aus T2
| |
| |- Element aus T2
| |
| |- Element aus T2
| |
| |-Element aus T2
|
| - Element aus T2
...
Wichtig hierbei ist, dass ein Element aus T1 niemals das Child eines Elements aus T2 seien kann und es auch immer nur ein Element aus T1 im Baum als Root gibt.
Der problematische Teil stellt nun also die Anordnung der Elemente aus T2 dar.
Ich suche jetzt nach Möglichkeit eine rekursive SQL Anweisung um die korrekte Baumstruktur zu bekommen.
Einzelne Elemente sehen dabei wie folgt aus (E1 = Element aus T1, E2 = Element aus T2):
E1.ID
E2.ID, E2.RefUebergeordneteID (kann sowohl eine E1.ID als auch eine E2.ID sein), E2.RefUebergeordneteE1 (wurde bereits von mir hinzugefügt um etwas sortieren zu können)
Die anderen Attribute sind hier unwichtig, es geht nur um die Zuordnung der IDs bzw. eben der referenzierten IDs.
Das Problem ist, dass die ID jeweils GUI-IDs sind und keine aufeinander folgenden Indizes. Diese Struktur kann ich auch nicht groß umstellen. Insgesamt habe ich leider wenig Möglichkeiten die bereits vorhandene Struktur zu erweitern, ließe sich aber ggf. drüber diskutieren .
Mein Ansatz sieht nun bisher wie folgt aus:
Code:
WITH RECURSIVE rek (ID, RefUebergeordneteID, RefUebergeordneteE1)
AS (
SELECT ID, RefUebergeordneteID, RefUebergeordneteE1
FROM T2
Where RefUebergeordneteID = ' <eine bestimmte GUI-ID>'
UNION ALL
SELECT child.ID, child.RefUebergeordneteID, child.RefUebergeordneteE1
FROM rek parent,
T2 child
WHERE parent.ID = child.RefUebergeordneteID
)
SELECT DISTINCT ID, RefUebergeordneteID, RefUebergeordneteE1
FROM rek
Was dann leider zu einem durcheinander gewürfelten Ergebnis führt, da immer automatisch nach der kleinsten GUI-ID sortiert wird. Rekursionen schachteln geht scheinbar nicht in SQl (? meines Wissens sind nur From, Select und Where schachtelbar), daher komme ich nicht wirklich weiter. Denn das aktuell Ergebnis kriege ich auch viel einfacher mit einem:
Code:
Select ID, RefUebergeordneteID, RefUebergeordneteE1
From T2
Where RefUebergeordneteE1 = ' <eine bestimmte GUI-ID>'
An sich dachte ich eben die Rekursion würde meine Elemente nach folgendem Schema ausgeben:
- hole alle T2.RefUebergeordneteID mit ' <eine bestimmte GUI-ID>' als Tabelle rek
- hole alle Childs mit T2.RefUebergeordneteID = rek.ID wiederum als rek usw.
Nur leider wird dann halt sortiert
Wichtig ist auch noch das eine nested Struktur nicht in Frage kommt, da ständig Daten in die Tabelle 2 der Datenbank an beliebigen Stellen geschrieben, kopiert oder verschoben werden können und dann irgendwann der Aufwand zu groß wird die ganze Struktur immer neu durchzurechnen.
Falls es noch wichtig bzw. von Interesse ist: Es geht darum mittels eines C# Programms halt auf eine Firebird DB zuzugreifen und sich dabei viele Selectes zu ersparen, da aktuell die Situation so ist das bestimmte große vom Programm gestellte Anfragen alles lahmlegen Denn aktuell laufen da viele while-Schleifen ineinander die alle fröglich ihre Selects abfeuern, was einerseits lange dauert, andererseits halt den Speicher doch recht extrem belastet. Die Rede ist hier von locker 15.000 - 20.000 Anfragen die da beim Laden rausgehen. Das habe ich nicht gemacht, dass war netterweise schon so und lief bisher auch ganz gut...solange die Projekte an sich klein genug waren Daher ist das problem wohl bisher nie aufgefallen. Nur jetzt muss der Firebird-Server (die Software nicht die Hardware wo die DBs liegen) plötzlich um die 1,8GB bewältigen, was in der Version 2.1 auch nur unter Linux geht. Unter Windows steigt er einfach aus, der 2.5er Beta läuft durch aber es dauert immernoch sau lange die Daten zu laden so ca. 7-10min. Und in absehbarer Zeit ist die 6-7 fache Datenmange zu erwarten hehe.
Wäre klasse wenn jemand vielleicht einen Denkanstoß bzw. einen Lösungsansatz hätte
.
EDIT :
.
Einen Schritt weiter aber leider noch nicht ganz fertig sieht das Ganze nun so aus:
Code:
WITH RECURSIVE rek (ID, RefUebergeordneteID, RefUebergeordneteE1, stufe)
AS (
SELECT ID, RefUebergeordneteID, RefUebergeordneteE1, 1 as stufe
FROM T2
Where RefUebergeordneteID = ' <eine bestimmte GUI-ID>'
UNION ALL
SELECT child.ID, child.RefUebergeordneteID, child.RefUebergeordneteE1, parent.stufe+1
FROM rek parent,
T2 child
WHERE parent.ID = child.RefUebergeordneteID
)
SELECT DISTINCT ID, RefUebergeordneteID, RefUebergeordneteE1, stufe
FROM rek
Order by stufe
Das Ergebnis ist schon mal besser, aber der "counter" mit der stufe zählt noch nicht richtig hoch. An sich müsste er an eienr anderen Stelle sitzen, aber da kann ich ihn nirgends reinsetzen .
Im Prinzip würde mir ein group by RefUebergeordneteID vor dem Order by womöglich helfen, aber das kann wohl auf Grund der Rekursion nicht angewendet werden.
So langsam glaube ich das ich mein Problem mit reinem SQL nicht lösen kann und die Anwendung da selber doch mal sortieren muss. Dann muss ich zwar wieder ein paar Sachen nachladen, aber ich kann noch irgendwie versuchen die monströse Anzahl der Selects zu reduzieren.
Aber vielleicht hat hier ja doch noch wer die rettende Idee
Zuletzt bearbeitet:
BoMbY
Grand Admiral Special
- Mitglied seit
- 22.11.2001
- Beiträge
- 7.468
- Renomée
- 293
- Standort
- Aachen
- Prozessor
- Ryzen 3700X
- Mainboard
- Gigabyte X570 Aorus Elite
- Kühlung
- Noctua NH-U12A
- Speicher
- 2x16 GB, G.Skill F4-3200C14D-32GVK @ 3600 16-16-16-32-48-1T
- Grafikprozessor
- RX 5700 XTX
- Display
- Samsung CHG70, 32", 2560x1440@144Hz, FreeSync2
- SSD
- AORUS NVMe Gen4 SSD 2TB, Samsung 960 EVO 1TB, Samsung 840 EVO 1TB, Samsung 850 EVO 512GB
- Optisches Laufwerk
- Sony BD-5300S-0B (eSATA)
- Gehäuse
- Phanteks Evolv ATX
- Netzteil
- Enermax Platimax D.F. 750W
- Betriebssystem
- Windows 10
- Webbrowser
- Firefox
Theoretisch müsste es funktionieren, wenn Du eine Stored-Procedure benutzt, welche sich selbst rekursiv aufruft - ich kenne mich aber mit Firebird zu wenig aus um das zu garantieren.
Onkel Homie
Gesperrt
- Mitglied seit
- 26.03.2003
- Beiträge
- 15.842
- Renomée
- 390
- Standort
- Dortmund
- Aktuelle Projekte
- Spinhenge, SIMAP, QMC, POEM
- Lieblingsprojekt
- Spinhenge
- Meine Systeme
- C2D E8400 @3,8GHz
- BOINC-Statistiken
- Mein Laptop
- Lenovo TP Edge 13 NV122GE, Thinkpad R60 9461-DXG T5600 2GB
- Prozessor
- i7-3770k
- Mainboard
- Asrock Z77 Extreme 4
- Kühlung
- Thermalright Macho 120
- Speicher
- Kingston 1600 CL9 4x4096
- Grafikprozessor
- GTX 770 4096
- Display
- Dell U2713HM, Samsung 226BW
- HDD
- 1 x Samsung 840 Pro SSD, 2 x WD10EZEX 1 TB Raid 1
- Soundkarte
- Realtek onboard
- Gehäuse
- Nanoxia Deep Silence 2
- Netzteil
- beQuiet Straight Power E9 580W
- Betriebssystem
- Windows 8.1 Pro 64, Windows 7 Pro 64, Xubuntu 14.04
- Webbrowser
- Chrome
- Verschiedenes
- NAS: Synology DS214play; Kamera: Nikon D7100, Nexus 7 2013
Stores Procedures kommen an sich wohl auch nicht so in Frage...so sagte man mir. Bin halt noch rehct neu an der Sache dran, aber man muss im Hinterkopd behalten das die Software häufiger upgedatet wird und eben jene Updates möglichst nicht die Datenbank betreffen sollten bzw. wenn dort was nötig ist, sollte dies möglichst einfach zu handeln sein. Kann sonst nämlich fiese Probleme bei den Kunden geben. (genau aus dem Grund hänge ich gerade an dem Kram *g*).
Ich bastel gearde schon an einer möglichen anderen Lösung.
Aber danke für den Vorschlag.
Firebird ist übrigens an sich schon recht striktes SQL, oder sind etwas anders umgesetzt, wie z.B. hier auch die Rekusrion. Im Netz findet man zumindest bei den Standard Beispielen nur WITH und nicht WITH RECURSIVE wie es bei Firebird seien muss.
Ich bastel gearde schon an einer möglichen anderen Lösung.
Aber danke für den Vorschlag.
Firebird ist übrigens an sich schon recht striktes SQL, oder sind etwas anders umgesetzt, wie z.B. hier auch die Rekusrion. Im Netz findet man zumindest bei den Standard Beispielen nur WITH und nicht WITH RECURSIVE wie es bei Firebird seien muss.
Ähnliche Themen
- Antworten
- 0
- Aufrufe
- 142K