Rekursive Tabelle
am 24.04.2006 21:13:46 von Stefan Christ
Guten Tag zusammen,
dies ist mein erstes Beitrag von mir in dieser Newsgroup, ich bitte um
etwas Nachsicht falls ich den einen oder anderen Fehler mache. Ich habe
ein Problem mit einer rekursiven Tabelle.
Diese Tabelle ist für die Navigation einer Website gedacht. Um
Unterpunkte anlegen zu können, hat jeder Punkt einen Vaterpunkt:
ID parentID Link
1 NULL news.php
2 1 archiv.php
3 NULL links.php
Dadurch versuche ich folgendes Menü zu realisieren:
news.php
- archiv.php
links.php
Mein Problem ist nun das Auslesen der Daten. Ich möchte nicht unnötig
viele Selects laufen lassen um die notwendigen Daten auszulesen. Mein
erster Ansatz war ein SELECT-Statement welches sofort alle Hauptpunkte
und Unterpunkte eines bestimmten Hauptpunktes zurückgibt. Leider ist
dazu mein Können aber zu klein.
Mein zweiter Anlaufpunkt war es, zunächst alle Hauptpunkte auszulesen
und dann mittels PHP nachträglich alle Kinder eines bestimmten Punktes
zu holen. Dann müsste ich die Daten mit PHP zusammenschleifen, mehr als
2 Ebenen sind damit aber auch schon umständlich.
Wie würdet ihr so etwas realisieren? Mehrere Statements und die
Ergebnisse mit PHP zurechtschleifen oder gibt es die Möglichkeit alles
mit einem Statement auszulesen? Habe schon mehrfach von sogenannten
"nested sets" gehört, diese scheinen aber schon eine höhere Wissensebene
vorauszusetzen.
Ich bin dankbar für jeden Tipp!
Grüsse,
Stefan
Re: Rekursive Tabelle
am 24.04.2006 22:02:36 von Niels Braczek
Stefan Christ schrieb:
> ID parentID Link
> 1 NULL news.php
> 2 1 archiv.php
> 3 NULL links.php
>
> Dadurch versuche ich folgendes Menü zu realisieren:
>
> news.php
> - archiv.php
> links.php
Die Struktur ist ok.
> Wie würdet ihr so etwas realisieren? Mehrere Statements und die
> Ergebnisse mit PHP zurechtschleifen oder gibt es die Möglichkeit alles
> mit einem Statement auszulesen? Habe schon mehrfach von sogenannten
> "nested sets" gehört, diese scheinen aber schon eine höhere Wissensebene
> vorauszusetzen.
Nested Sets bieten dir hier kaum einen Vorteil.
Lies die komplette Tabelle in ein Array, zB. $items.
Dann durchläufst du das Array zweimal. Im ersten Durchlauf sammelst du
die Kinder:
foreach ($items as $k => $item) {
if (!empty($item['parentID'])) {
$items['parentID']['children'][] =& $items[$k];
}
}
Im zweiten Durchlauf entfernst du alle Kindeinträge auf der Hauptebene.
foreach ($items as $k => $item) {
if (!empty($item['parentID'])) {
unset($items[$k]);
}
}
Dadurch solltest du ein Array haben (ich habe das jetzt nicht
ausprobiert), das deine Menüstruktur genau abbildet. Überprüfen kannst
du das mit
var_dump($items);
MfG
Niels
--
| http://www.kolleg.de · Das Portal der Kollegs in Deutschland |
| http://www.bsds.de · BSDS Braczek Software- und DatenSysteme |
| Webdesign · Webhosting · E-Commerce · Mambo Content Management |
------------------------------------------------------------ ----
Re: Rekursive Tabelle
am 24.04.2006 22:37:29 von Michael Fesser
..oO(Niels Braczek)
>Lies die komplette Tabelle in ein Array, zB. $items.
>Dann durchläufst du das Array zweimal. Im ersten Durchlauf sammelst du
>die Kinder:
>
>foreach ($items as $k => $item) {
> if (!empty($item['parentID'])) {
> $items['parentID']['children'][] =& $items[$k];
$items[$item['parentID']]['children'][] =& $items[$k];
Micha
Re: Rekursive Tabelle
am 24.04.2006 23:04:06 von Stefan Christ
Michael Fesser wrote:
> .oO(Niels Braczek)
>
>> Lies die komplette Tabelle in ein Array, zB. $items.
>> Dann durchläufst du das Array zweimal. Im ersten Durchlauf sammelst du
>> die Kinder:
>>
>> foreach ($items as $k => $item) {
>> if (!empty($item['parentID'])) {
>> $items['parentID']['children'][] =& $items[$k];
>
> $items[$item['parentID']]['children'][] =& $items[$k];
>
> Micha
Vielen Dank für die Hilfe, ich werde morgen mal versuchen ob ich das
hinbekomme.
MfG
Stefan
Re: Rekursive Tabelle
am 24.04.2006 23:39:35 von Niels Braczek
Michael Fesser schrieb:
> .oO(Niels Braczek)
>
>>Lies die komplette Tabelle in ein Array, zB. $items.
>>Dann durchläufst du das Array zweimal. Im ersten Durchlauf sammelst du
>>die Kinder:
>>
>>foreach ($items as $k => $item) {
>> if (!empty($item['parentID'])) {
>> $items['parentID']['children'][] =& $items[$k];
>
> $items[$item['parentID']]['children'][] =& $items[$k];
Natürlich!
MfG
Niels
--
| http://www.kolleg.de · Das Portal der Kollegs in Deutschland |
| http://www.bsds.de · BSDS Braczek Software- und DatenSysteme |
| Webdesign · Webhosting · E-Commerce · Mambo Content Management |
------------------------------------------------------------ ----
Re: Rekursive Tabelle
am 25.04.2006 19:29:48 von Stefan Christ
Niels Braczek wrote:
> Stefan Christ schrieb:
>
>> ID parentID Link
>> 1 NULL news.php
>> 2 1 archiv.php
>> 3 NULL links.php
>>
>> Dadurch versuche ich folgendes Menü zu realisieren:
>>
>> news.php
>> - archiv.php
>> links.php
>
> Die Struktur ist ok.
>
>> Wie würdet ihr so etwas realisieren? Mehrere Statements und die
>> Ergebnisse mit PHP zurechtschleifen oder gibt es die Möglichkeit alles
>> mit einem Statement auszulesen? Habe schon mehrfach von sogenannten
>> "nested sets" gehört, diese scheinen aber schon eine höhere Wissensebene
>> vorauszusetzen.
>
> Nested Sets bieten dir hier kaum einen Vorteil.
> Lies die komplette Tabelle in ein Array, zB. $items.
> Dann durchläufst du das Array zweimal. Im ersten Durchlauf sammelst du
> die Kinder:
>
> foreach ($items as $k => $item) {
> if (!empty($item['parentID'])) {
> $items['parentID']['children'][] =& $items[$k];
> }
> }
>
> Im zweiten Durchlauf entfernst du alle Kindeinträge auf der Hauptebene.
>
> foreach ($items as $k => $item) {
> if (!empty($item['parentID'])) {
> unset($items[$k]);
> }
> }
>
> Dadurch solltest du ein Array haben (ich habe das jetzt nicht
> ausprobiert), das deine Menüstruktur genau abbildet. Überprüfen kannst
> du das mit
>
> var_dump($items);
>
> MfG
> Niels
>
Hallo nochmals,
durch die beiden Schleifen konnte ich erfolgreich ein mehrdimensionales
Array erzeugen. Durch das unset() wird aber ein Elements gelöscht, der
Index wird dennoch beibehlten. Um dies zu verhinden habe ich
nachträglich versucht mittels
array_splice($items, $k, 1);
den Index fortlaufend zu halten. Dies ist nun auch der Fall, allerdings
sah der anschliessende var_dump() wie folgt aus:
...
[2]=>
&array(3) {
["id"]=>
string(1) "5"
["target"]=>
string(11) "subnavi.php"
["parent"]=>
string(1) "2"
}
...
Was mich stuzig macht ist das "&" vor array. Dies taucht nicht bei jedem
Array auf, nur bei einigen. Woran könnte dies denn liegen? Oder gibt es
eine performantere Möglichkeit als mit array_splice?
MfG
Stefan
Re: Rekursive Tabelle
am 25.04.2006 21:41:32 von Niels Braczek
Stefan Christ schrieb:
> Niels Braczek wrote:
>> foreach ($items as $k => $item) {
>> if (!empty($item['parentID'])) {
>> $items['parentID']['children'][] =& $items[$k];
>> }
>> }
>>
>> foreach ($items as $k => $item) {
>> if (!empty($item['parentID'])) {
>> unset($items[$k]);
>> }
>> }
> durch die beiden Schleifen konnte ich erfolgreich ein mehrdimensionales
> Array erzeugen. Durch das unset() wird aber ein Elements gelöscht, der
> Index wird dennoch beibehlten.
Das ist planvolle Absicht. Es handelt sich dabei um die ID des Eintrags.
Es gibt *keinen* Anlass, den Index fortlaufend haben zu wollen.
> Um dies zu verhinden habe ich
> nachträglich versucht mittels
>
> array_splice($items, $k, 1);
Damit machst du das Array kaputt.
> Was mich stuzig macht ist das "&" vor array. Dies taucht nicht bei jedem
> Array auf, nur bei einigen. Woran könnte dies denn liegen?
Das liegt daran, dass beim Aufbau des Baumes nicht das ganze Element,
sondern nur eine Referenz darauf verwendet wurde. Mehr dazu im Manual:
http://www.php.net/manual/en/language.references.php
MfG
Niels
--
| http://www.kolleg.de · Das Portal der Kollegs in Deutschland |
| http://www.bsds.de · BSDS Braczek Software- und DatenSysteme |
| Webdesign · Webhosting · E-Commerce · Mambo Content Management |
------------------------------------------------------------ ----
Re: Rekursive Tabelle
am 25.04.2006 22:24:37 von Stefan Christ
Niels Braczek wrote:
> Stefan Christ schrieb:
>> Niels Braczek wrote:
>
>>> foreach ($items as $k => $item) {
>>> if (!empty($item['parentID'])) {
>>> $items['parentID']['children'][] =& $items[$k];
>>> }
>>> }
>>>
>>> foreach ($items as $k => $item) {
>>> if (!empty($item['parentID'])) {
>>> unset($items[$k]);
>>> }
>>> }
>
>> durch die beiden Schleifen konnte ich erfolgreich ein mehrdimensionales
>> Array erzeugen. Durch das unset() wird aber ein Elements gelöscht, der
>> Index wird dennoch beibehlten.
>
> Das ist planvolle Absicht. Es handelt sich dabei um die ID des Eintrags.
> Es gibt *keinen* Anlass, den Index fortlaufend haben zu wollen.
>
>> Um dies zu verhinden habe ich
>> nachträglich versucht mittels
>>
>> array_splice($items, $k, 1);
>
> Damit machst du das Array kaputt.
>
>> Was mich stuzig macht ist das "&" vor array. Dies taucht nicht bei jedem
>> Array auf, nur bei einigen. Woran könnte dies denn liegen?
>
> Das liegt daran, dass beim Aufbau des Baumes nicht das ganze Element,
> sondern nur eine Referenz darauf verwendet wurde. Mehr dazu im Manual:
> http://www.php.net/manual/en/language.references.php
>
> MfG
> Niels
>
Der Index ist leider nicht gleich der ID in der Datenbank!
[0]=>
array(3) {
["id"]=>
string(1) "1"
["target"]=>
string(8) "news.php"
["parent"]=>
NULL
}
[2]=>
array(4) {
["id"]=>
string(1) "2"
["target"]=>
string(10) "archiv.php"
["parent"]=>
NULL
Das Array beginnt mit dem Index 0 und enthält als ID die 1, was richtig
ist, danach folgt bereits Index 2.
Entweder ich habe eine deiner vorigen Nachrichten falsch interpretiert
und ich habe das Array nun falsch aufgebaut, oder wir reden schon wieder
aneinander vorbei. Meiner Ansicht nach wäre dieses Array wesentlich
schön wenn es fortlaufende Indizes hätte.
MfG
Stefan
Re: Rekursive Tabelle
am 26.04.2006 00:00:59 von Michael Fesser
..oO(Stefan Christ)
>durch die beiden Schleifen konnte ich erfolgreich ein mehrdimensionales
>Array erzeugen. Durch das unset() wird aber ein Elements gelöscht, der
>Index wird dennoch beibehlten. Um dies zu verhinden habe ich
>nachträglich versucht mittels
>
>array_splice($items, $k, 1);
Nimm das wieder raus, damit zerstörst Du die Baumstruktur. Was gibt denn
var_dump() direkt nach Erzeugen des Arrays aus?
Micha
Re: Rekursive Tabelle
am 26.04.2006 00:11:14 von Niels Braczek
Stefan Christ schrieb:
> Niels Braczek wrote:
>> Das ist planvolle Absicht. Es handelt sich dabei um die ID des Eintrags.
>> Es gibt *keinen* Anlass, den Index fortlaufend haben zu wollen.
> Der Index ist leider nicht gleich der ID in der Datenbank!
>
> Das Array beginnt mit dem Index 0 und enthält als ID die 1, was richtig
> ist, danach folgt bereits Index 2.
>
> Entweder ich habe eine deiner vorigen Nachrichten falsch interpretiert
> und ich habe das Array nun falsch aufgebaut, oder wir reden schon wieder
> aneinander vorbei. Meiner Ansicht nach wäre dieses Array wesentlich
> schön wenn es fortlaufende Indizes hätte.
Nein, ich habe eine für mich selbstverständliche Information
unterschlagen. Das von mir vorgeschlagene Vorgehen setzt voraus, dass
die Datensätze über ihre ID indiziert sind. Es wird also etwa so aufgebaut:
$sql = "SELECT ...";
$result = mysql_query($sql) or die($sql.'
'.mysql_error());
$items = array();
while ($row = mysql_fetch_assoc($result)) {
$items[$row['id']] = $row;
}
mysql_free_result($result);
MfG
Niels
--
| http://www.kolleg.de · Das Portal der Kollegs in Deutschland |
| http://www.bsds.de · BSDS Braczek Software- und DatenSysteme |
| Webdesign · Webhosting · E-Commerce · Mambo Content Management |
------------------------------------------------------------ ----
Re: Rekursive Tabelle
am 26.04.2006 20:06:07 von Stefan Christ
Niels Braczek wrote:
> Stefan Christ schrieb:
>> Niels Braczek wrote:
>
>>> Das ist planvolle Absicht. Es handelt sich dabei um die ID des Eintrags.
>>> Es gibt *keinen* Anlass, den Index fortlaufend haben zu wollen.
>
>> Der Index ist leider nicht gleich der ID in der Datenbank!
>>
>> Das Array beginnt mit dem Index 0 und enthält als ID die 1, was richtig
>> ist, danach folgt bereits Index 2.
>>
>> Entweder ich habe eine deiner vorigen Nachrichten falsch interpretiert
>> und ich habe das Array nun falsch aufgebaut, oder wir reden schon wieder
>> aneinander vorbei. Meiner Ansicht nach wäre dieses Array wesentlich
>> schön wenn es fortlaufende Indizes hätte.
>
> Nein, ich habe eine für mich selbstverständliche Information
> unterschlagen. Das von mir vorgeschlagene Vorgehen setzt voraus, dass
> die Datensätze über ihre ID indiziert sind. Es wird also etwa so aufgebaut:
>
> $sql = "SELECT ...";
> $result = mysql_query($sql) or die($sql.'
'.mysql_error());
> $items = array();
> while ($row = mysql_fetch_assoc($result)) {
> $items[$row['id']] = $row;
> }
> mysql_free_result($result);
>
> MfG
> Niels
>
Okay daran hatte ich anfangs nicht gedacht. Nehme ich die ID als Index,
so ist das Array nahezu korrekt. Ein kleinerer Fehler ist mir noch
aufgefallen:
$items[$item['parentID']]['children'][] =& $items[$k];
Damit auch die Kinder als Index ihre ID bekommen, habe ich dies durch
folgende Zeile ersetzt:
$items[$item["parent"]]["children"][$k] =& $items[$k];
Vielen Dank für Eure Hilfe, nun werde ich mal versuchen, damit
weiterzustricken. Mein Ziel ist eine Navigation einer Website, dabei
sollen die Kinder aber nur dann angezeigt werden, wenn das entsprechende
Elternelement angeklickt wurde oder aber eines dieser Kinder.
Mal sehen wie weit ich komme.
Danke,
Stefan
Re: Rekursive Tabelle
am 27.04.2006 00:16:40 von Niels Braczek
Stefan Christ schrieb:
> Okay daran hatte ich anfangs nicht gedacht. Nehme ich die ID als Index,
> so ist das Array nahezu korrekt. Ein kleinerer Fehler ist mir noch
> aufgefallen:
>
> $items[$item['parentID']]['children'][] =& $items[$k];
>
> Damit auch die Kinder als Index ihre ID bekommen, habe ich dies durch
> folgende Zeile ersetzt:
>
> $items[$item["parent"]]["children"][$k] =& $items[$k];
Das kann man machen, ist aber technisch gesehen nicht erforderlich, da
alle Elemente immer über die oberste Ebene eingehängt wurden. Vielleicht
ist es nützlich -- schaden tut's auf keinen Fall. Ich bin also dafür ;-)
MfG
Niels
--
| http://www.kolleg.de · Das Portal der Kollegs in Deutschland |
| http://www.bsds.de · BSDS Braczek Software- und DatenSysteme |
| Webdesign · Webhosting · E-Commerce · Mambo Content Management |
------------------------------------------------------------ ----
Re: Rekursive Tabelle
am 02.05.2006 17:13:14 von do.not.REMOVETHAT
Stefan Christ schrieb:
> Ich habe ein Problem mit einer rekursiven Tabelle.
>
> Diese Tabelle ist für die Navigation einer Website gedacht.
Relevant ist, wie Du den "aktuellen Punkt" kennzeichnest. Wenn Du den
Pfad vom Root-Element zum aktuellen Element in der URL abbildest, dann
ist das ganz einfach. Das Empfielt sich auch für "schöne URLs" und die
lieben Suchmaschinen, die in der URL gerne das eine oder andere Keyword
finden...
(http://www.trullala.de/)foo/bar/baz
Explode "foo/bar/baz" nach "/". Baue Dir eine Query zusammen mit der Du
die Tabelle n (= Anzahl der Elemente) miteinander joinst - plus einmal
für die unterpunkte (die willst Du ja auch haben)
from tab as ebene1
left join tab as ebene2 on ebene2.parent = ebene1.id
left join tab as ebene3 on ebene3.parent = ebene2.id
left join tab as ebene4 on ebene4.parent = ebene3.id
....und dann die Geschwister, die braucht man auch für's Menü:
left join tab as sister1 on ebene1.parent = sister1.parent
left join tab as sister2 on ebene2.parent = sister2.parent
left join tab as sister3 on ebene3.parent = sister3.parent
ein bisschen where und select - fertig hast Du genau die Daten, die Du
brauchst.
Grüße, Matthias