Hallo,
es ist mir vollkommen klar, dass das ein ziemlich und ausserdem
unnötig kompliziertes Konstrukt ist. Und ich wüsste, dass und
wie ich es heute anders machen würde. Es steht zur Zeit aber
nicht zur Debatte, dieses Kontrukt an sich zu ändern.
konnte ich das wissen? Nein, Du hattest es vorher nicht gesagt.
Obwohl ich mittlerweile dafon ausgehe, dass mich die Diskussion
hier in meinem Vorhaben nicht weiterbringen wird, weil ich mein
- unnötig kompliziertes - Konstrukt und das, was ich eigentlich
vorhabe nicht erklären können werde, will ich es noch einmal
versuchen:
Das mit dem Elternelement hatte ich versucht zu erläutern.
Der Wert 0 in einem der Felder 'd0'-'d3' zeichnet einen
Datensatz als Elternelement aus. Der in der Tabelle 'structure'
erste Datensatz ist das Elternelement des zweiten und der
zweite Elternelement des ersten.
in Tabellen gibt es keine "Ordnung", es sei denn Du sortierst nach einem Sortierkriterium.
site_id d0 d1 d2 d3 titles 7 2 2 0 0 string5/string7
Ich denke, dass ich mit JOINS ein Resultset hinbekomme, dass
so aussieht:
mit Joins und 'ner UNION
site_id | d0 | d1 | d2 | d3 | title_0 | title_1 | title_2 | title_3 |
--------|----|----|----|----|-----------------------------|---------|
1 1 0 0 0 string1 NULL NULL NULL 2 1 1 0 0 string1 string2 NULL NULL -------- ---- ---- ---- ---- ----------------------------- --------- 2 1 1 0 0 string1 string2 string3 NULL -------- ---- ---- ---- ---- ----------------------------- --------- 2 1 1 0 0 string1 string2 string3 string4 -------- ---- ---- ---- ---- ----------------------------- ---------
und noch ein bisschen besser. Um aber wirklich zu sehen, wie's richtig funktioniert, wären noch ein paar Datensätze zusätzlich sinnvoll :-)
OK, fangen wir an:
1. Abfrage: ermittle alle Einträge nullter Ebene
Bedingung: d0 <> 0, d1 bis d3 alle gleich 0
SELECT
s.site_id,
s.d0,
s.d1,
s.d2,
s.d3,
c.title title_0,
NULL title_1,
NULL title_2,
NULL title_3
c.title titles
FROM
structure s
INNER JOIN
content c
ON
s.site_id = c.site_id
WHERE
s.d0 <> 0 AND s.d1 = 0 AND s.d2 = 0 AND s.d3 = 0
Ergebnis:
site_id d0 d1 d2 d3 title_0 title_1 title_2 title_3 titles
-------- --- --- --- --- -------- -------- -------- -------- ----------
1 1 0 0 0 string1 NULL NULL NULL string1
5 2 0 0 0 string5 NULL NULL NULL string5
2. Abfrage: Ermittle alle Einträge der ersten Ebene
Einträge der ersten Ebene haben in d2 und d3 die Werte 0
Das Elternelement bekomme ich zum Beispiel über einen Selfjoin der structure-Tabelle mit sich selbst und Gleichheit in der Spalte d0. Zusätzlich gilt, dass das Elternelement in den Spalten d1, d2 und d3 den Wert 0 hat. Die Titel bekommen wir jeweils durch einen Join mit der content-Tabelle:
SELECT
s1.site_id,
s1.d0,
s1.d1,
s1.d2,
s1.d3,
c0.title title_0,
c1.title title_1,
NULL title_2,
NULL title_3,
CONCAT(c0.title, '/', c1.title) titles
FROM
structure s1
INNER JOIN
structure s0
ON
s1.d0 = s0.d0 AND s0.d1 = 0 AND s0.d2 = 0 AND s0.d3 = 0
INNER JOIN
content c0
ON
s0.site_id = c0.site_id
INNER JOIN
content c1
ON
s1.site_id = c1.site_id
WHERE
s1.d0 <> 0 AND s1.d1 <> 0 AND s1.d2 = 0 AND s1.d3 = 0;
Ergebnis:
site_id d0 d1 d2 d3 title_0 title_1 title_2 title_3 titles
-------- --- --- --- --- -------- -------- -------- -------- -------
2 1 1 0 0 string1 string2 NULL NULL string1/string2
6 2 1 0 0 string5 string6 NULL NULL string5/string6
7 2 2 0 0 string5 string7 NULL NULL string5/string7
3. Abfrage: Ermittle alle Einträge der zweiten Ebene
Einträge der zweiten Ebene haben in d0, d1 und d2 Inhalte ungleich 0, in d3 den Wert 0 (WHERE-Klausel).
Das Elternlement aus der ersten Ebene bekommen wir durch einen Selfjoin mit der Bedingung, dass d0 und d1 gleiche Inhalte haben und der Elterndatensatz in den Spalten d2 und d3 den Wert 0 aufweist.
Das Elternelement der nullten Ebene bekommen wir durch einen weiteren Selfjoin genau wie in der zweiten Abfrage.
Danach joinen wir dreimal mit der content-Tabelle und bekommen somit die Inhalte für title_0 bis title_2, title_3 ist bei Einträgen der zweiten Ebene NULL.
SELECT
s2.site_id,
s2.d0,
s2.d1,
s2.d2,
s2.d3,
c0.title title_0,
c1.title title_1,
c2.title title_2,
NULL title_3,
CONCAT(c0.title, '/', c1.title, '/', c2.title) titles
FROM
structure s2
INNER JOIN
structure s1
ON
s2.d0 = s1.d0 AND s2.d1 = s1.d1 AND s1.d2 = 0 AND s1.d3 = 0
INNER JOIN
structure s0
ON
s1.d0 = s0.d0 AND s0.d1 = 0 AND s0.d2 = 0 AND s0.d3 = 0
INNER JOIN
content c0
ON
s0.site_id = c0.site_id
INNER JOIN
content c1
ON
s1.site_id = c1.site_id
INNER JOIN
content c2
ON
s2.site_id = c2.site_id
WHERE
s2.d0 <> 0 AND s2.d1 <> 0 AND s2.d2 <> 0 AND s2.d3 = 0;
Ergebnis:
site_id d0 d1 d2 d3 title_0 title_1 title_2 title_3 titles
------- -- -- -- -- ------- ------- ------- ------- -------
3 1 1 1 0 string1 string2 string3 NULL string1/string2/string3
Noch grausamer wird es für Ebene 3: Dreifacher Selfjoin der structure-Tabellen, um die Elternbeziehung vom Blatt bis zur Wurzel aufzulösen und vierfache Verjoinung mit den content-Tabellen, aber ganz analog zum bisherigen Vorgehen.
SQL und Ergebnis weggelassen :-)
Nun können wir die vier Abfragen per UNION verbinden und bekommen in titles die gewünschten Werte mittels einer einzigen (und ganz sicher nicht besonders performanten Abfrage). Möglicherweise kann man über ähnlich komplizierte verschachtelte Subselects das ganze auch hinbekommen und sich von EXPLAIN erklären lassen, was weniger unperformant ist.
Es bleibt das Problem, dass MySQL es jedoch nicht zulässt, was Du festgestellt hast.
... aber nicht ob das als Subselect für ein Update gehen
würde, weil ich in dem Subselect auf die selbe Tabelle
zugreife, die ich updaten will. Buw. wie ich anders da
heran gehen sollte.
Diese Problem kannst Du zum Beispiel dadurch lösen, dass Du das Ergebnis in eine temporäre Tabelle schreibst und anschließend das Update der structure-Tabelle mit Hilfe der temporären Tabelle vornimmst. Zusätzlich musst Du sicherstellen, dass keine Änderungen zwischen diesen beiden Schritten vorgenommen werden, zum Beispiel durch explizites Sperren der beteiligten Tabellen. (Das versäumt übrigens Dein Beispiel-PHP-Code).
Es sollte allerdings nur einmal erforderlich sein, die ganze Tabelle upzudaten. Bei Änderungen in Tabelle content sollten nur die betroffenen Datensätze geändert werden, was in erträglicher Geschwindigkeit erfolgen könnte.
Freundliche Grüße
Vinzenz