Hierarchikus adatkezelés SQL-lel PHP-ben I.
Adatainkat gyakran hierarchikus struktúrában tároljuk. Gondoljunk például a fájlrendszer esetén a könyvtárszerkezetre, de rengeteg más példát is találhatunk. És hogy szakmánál maradjunk: ilyen a többszintű menük vagy például a fórumok témáinak szerkezete. Ha eddig nem volt ötleted, hogy hogyan tudnál ilyen jellegű adatokat eltárolni, megmutatok pár módszert rávilágítva az egyes buktatókra.
Cikkünk a sitepoint.com Storing Hierarchical Data in a Database cikkje alapján készült.
Maga a fa struktúra elég egyszerűen néz ki:
Egy képzeletbeli fórum témaszerkezetén fogom bemutatni a megoldást, melynek váza a következőképpen néz ki:
A megoldásokban kétféleképpen tárolhatjuk az adatokat:
Az első megoldás előnye, hogy az fa egyes elemi, szintjei tárolhatnak különböző jellegű adatokat, míg a második megoldásban az egyes elemek mindig ugyanolyan típusú elemeket tárolnak.
Persze itt is léteznek kerülőutak (ahogy adatbázis kezelésben általában), de ezek kifejtése nem témája ezen cikknek.
A fenti példához az adattárolás második módszerét fogjuk használni a szemléletesség kedvéért.
Mint láttuk ez egy rekurzív függvény ami a következőképpen működik:
Hogy az egész fát megmutassuk, üres stringet kell használni a szülőhöz(
Meghívva tehát a függvényt:
Ha egy konkrét elem alá tartozó elemeket akarjuk lekérdezni (példának kedvéért legyen a "PHP"), akkor a függvény meghívása a következőre módosul:
Maga a függvény egy tömböt fog visszaadni, ami a
Használata egyszerű: megadjuk a kívántVisszaadja:
■ Cikkünk a sitepoint.com Storing Hierarchical Data in a Database cikkje alapján készült.
A sorozatban megjelent
- Hierarchikus adatkezelés SQL-lel PHP-ben I.
- Hierarchikus adatkezelés SQL-lel PHP-ben II.
- Hierarchikus adatkezelés SQL-lel PHP-ben III.
Példaprobléma
Maga a probléma, mint láttuk elég általános, mégse feltétlenül tudunk rá jól használható és hatékony megoldást. Ebben a cikkben megpróbálok bemutatni két megoldást, és közülük a hatékonyabbhoz a konkrét PHP-s megvalósítást is megnézzük egy erre a célra kialakított osztály képében.Maga a fa struktúra elég egyszerűen néz ki:
- a fának van egy gyökere
- a gyökérből ágazhatnak ki ágak, azoknak lehetnek további ágai
- ha egy ágnak nincsenek további ágai, akkor az ágat levélnek hívjuk
A cikkben alkalmazott megközelítéssel először Gijs Van Tulder Storing Hierarchical Data in a Database című cikkében találkoztunk, a sitepoint.com honlapon. A következőkben olvasható kódrészletek a fenti cikkben található példákon alapulnak.
Egy képzeletbeli fórum témaszerkezetén fogom bemutatni a megoldást, melynek váza a következőképpen néz ki:
Programozás
|-PHP
| |-Stringkezelés
| |-PEAR
| |-Mail
| |-HttpClient
|
|-HTML
|-CSS
| |-kiválasztók
|-XHTML
|-PHP
| |-Stringkezelés
| |-PEAR
| |-HttpClient
|
|-HTML
|-CSS
| |-kiválasztók
|-XHTML
Elméleti háttér
Az adatok tárolását valamilyen adatbázis kezelőben szeretnénk megvalósítani; legyen ez az egyszerűség kedvéért a MySQL, úgyis nemrég került fel egy hasznos cikk a telepítéséről: MySQL 4.1 telepítése Windows rendszereken.A megoldásokban kétféleképpen tárolhatjuk az adatokat:
- csak a fa struktúráját tároljuk el a fa táblánkban és a hozzá kapcsolódó adatokat külön táblá(k)ban tároljuk
- az adatokat és a fastruktúrát egy azon táblában tároljuk
Az első megoldás előnye, hogy az fa egyes elemi, szintjei tárolhatnak különböző jellegű adatokat, míg a második megoldásban az egyes elemek mindig ugyanolyan típusú elemeket tárolnak.
Persze itt is léteznek kerülőutak (ahogy adatbázis kezelésben általában), de ezek kifejtése nem témája ezen cikknek.
Függőségi modell
Első megoldásként az egyszerű és elegánsnak tűnő függőségi modellt fogom bemutatni. Azért elegáns, mert maga az eltárolás elég egyszerű, és egyetlen függvényre van szükség a fa lekérdezéséhez.A fenti példához az adattárolás második módszerét fogjuk használni a szemléletesség kedvéért.
+-------------+--------------+
| szulo | felirat |
+-------------+--------------+
| | Programozás |
| Programozás | PHP |
| PHP | Stringkezelés|
| PHP | PEAR |
| PEAR | Mail |
| PEAR | HttpClient |
| Programozás | HTML |
| HTML | CSS |
| CSS | kiválasztók |
| HTML | XHTML |
+-------------+--------------+
| szulo | felirat |
+-------------+--------------+
| | Programozás |
| Programozás | PHP |
| PHP | Stringkezelés|
| PHP | PEAR |
| PEAR | Mail |
| PEAR | HttpClient |
| Programozás | HTML |
| HTML | CSS |
| CSS | kiválasztók |
| HTML | XHTML |
+-------------+--------------+
A fa lekérdezése
Most hogy már megvan az adattáblánk, már csak meg kell jeleníteni azt valahogy. Kiindulásként a gyökér elemtől indulunk, ami az az elem, amelyiknek ugye nincs szülője (példánkban ez a "Programozás" elem).
<?php
// $szulo a szülőeleme a gyereknek amit látni szeretnénk
// $szint növekszik, ahogy mélyebbre megyünk a fában
// ezt használjuk hogy szépen beljebb kerüljenek a fa elemi
function displayChildren($szulo, $szint) {
// visszakapjuk a $szulo összes gyerekét
$result = mysql_query('SELECT felirat FROM tree '.
'WHERE szulo="'.$szulo.'";');
// minden gyermeket megjelenítünk
while ($row = mysql_fetch_array($result)) {
// beljebb toljuk és megjelenítjük a gyerek feliratát
echo str_repeat(' ',$szint).$row['title']."\n";
// újból meghívjuk a függvényt hogy megjelenítsük a gyerek gyerekeit
displayChildren($row['title'], $szint+1);
}
}
?>
- Lekérdezi az elem gyerekeit.
- Megjeleníti az elem gyerekét (megfelelően beljebb tolva).
- Innen az 1. ponttal folytatja, egészen addig, amíg vannak az elemnek gyerekei, egyébként veszi a következő elemet, ami egy szinten van ezzel.
Hogy az egész fát megmutassuk, üres stringet kell használni a szülőhöz(
$szulo=''
) és $szint=0
-t a mélységhez.Meghívva tehát a függvényt:
displayChildren('', 0);
a következő kimenetet kapjuk:Programozás
PHP
Stringkezelés
PEAR
Mail
HttpClient
HTML
CSS
kiválasztók
XHTML
PHP
Stringkezelés
PEAR
HttpClient
HTML
CSS
kiválasztók
XHTML
Ha egy konkrét elem alá tartozó elemeket akarjuk lekérdezni (példának kedvéért legyen a "PHP"), akkor a függvény meghívása a következőre módosul:
displayChildren('PHP', 0);
Út egy ághoz
Hogy eljussunk egy konkrét ághoz a fában, egy szintén rekurzív függvényt kell használnunk, ami nagyban hasonlít az előzőhöz.- Lekérdezi az elem szülőjét.
- Hozzáadja az elem szülőjét az elérési út elejéhez.
- Ha ez nem a gyökér elem, akkor folytatja az 1-es lépéssel.
- Visszaadja az elérési utat.
<?php
// $node az ág neve, aminek le akarjuk kérdezni az elérését a fában
function getPath($node) {
// megkeressük az ág szülőjét a fában
$result = mysql_query('SELECT szulo FROM tree '.
'WHERE felirat="'.$node.'";');
$row = mysql_fetch_array($result);
// elmentjük az elérési utat egy tömbben
$path = array();
// csak akkor folytatjuk ha a $node ág nem a gyökér
// (annak ugyanis nincsen szülője)
if ($row['szulo']!='') {
// az utolsó eleme az elérési útnak a szülő eleme a $node ágnak
$path[] = $row['szulo'];
// hozzá kell adni a szülő elemet az elérési úthoz
$path = array_merge(getPath($row['szulo']), $path);
}
// visszaadjuk az elérési utat
return $path;
}
?>
felirat
-okat a gyökértől induló sorrendben fogja tartalmazni.Használata egyszerű: megadjuk a kívánt
felirat
nevét, és visszakapjuk az elérési útját egy tömbben. Például:
print_r(getPath('PEAR'));
Array
(
[0] => Programozás
[1] => PHP
[2] => PEAR
)
(
[0] => Programozás
[1] => PHP
[2] => PEAR
)
Összefoglalás
Mint láttuk ezek az függvények eléggé egyszerűen használhatók, csak sajnos rekurzívak. Ez bonyolult faszerkezetnél meglassítja az eredmény kijelzését, ugyanis minden egyes elemnél egy új SQL lekérdezés történik (képzeljük el például, hogy egy több ezer tételes kategóriák szerint strukturált könyvtári adatbázisról van szó). Ilyen esetekre sajnos nem elég hatékony, ezért a következő cikkemben bemutatok egy sokkal hatékonyabb megoldást ezen problémák leküzdésére. Illetve annyit szeretnék még megjegyezni, hogy vannak olyan adatbázis kezelők, melyek támogatják a hierarchikus adatlekérdezéseket, és a fent taglalt adatbázis struktúra esetén is lehetőségünk van a teljes fa, vagy csak egy részének lekérdezésére egyetlen query-vel. Például Oracle esetén rendelkezésünkre áll aCONNECT BY
szerkezet.
A téma érdekes
Egyébként szerencsésebb lenne a címben a "struktúrált"-at "hierarchikus"-ra változtatni, az adatbázisban ugyanis általában pont struktúrált adatokat tárolunk, ami nem feltétlenül jelenti, hogy azok vaamilyen hierarchiát alkotnak.
P][G
Cím változott
Köszi
--------
Poetro
Gagyi
Re: Gagyi
Szerencsére a kezdők is elég gyakran látogatják az oldalt és nekik mindenképpen segítségként szolgál.
A cikk következő részében már egy jóval komolyabb dologról lesz szó, ami már remélem elnyeri a tetszésedet.
--------
Poetro
Visszavonom
tobb reszes cikkek es menu pelda
A javaslatom annyi lenne, hogy a tobb reszes cikkek cimeben legyen jelolve, hogy ez csak az elso resz. Vagy peldaul bevezeto, alapok, kezdoknek stb. Igy mindenki tudja mire szamithat.
Ez a cikk kicsit karcsu az eddigiekhez kepest, de mindenkeppen hasznos kezdoknek! Viszont talan eppen a kezdoknek van szukseguk tenyleg preciz mintakra. Lasd elottem az ID-s hozzaszolast. Lehetett volna picit reszletezni jobban az adatbazis szerkezetet.
A forum pelda helyett, vagy mellett lehetne egy tobb szintes menu, UL listas kiirasara pelda. Persze ez mar nem nagy lepes innen megvalositani, de abban az esetben egy rogton felhasznalhato kodreszlet lenne. Hiszen egy UL-s listat CSS-sel formazhatunk utana anelkul, hogy a PHP-hoz hozzákéne nyulnunk. (Es ugye van egy apro buktato is az egymasba agyazott listaknal az UL-LI sorrendet illetoen: a PHP-s kiirasnal nem szabad addig lezarni az adott LI-t mig a gyerek listat ki nem irtuk.)
Köszönöm a kritikát
--------
Poetro
Köszönöm
ha...
Na ne már
Didaktikai szempontok
Volt egy ismerosom akit kiskoraban nagyon feltettek a szulei ezert mindig elkaptak, ha el akart esni. Na olyan szep betonfejeseket ritkan latsz amiket a srac produkalt. Elobb suhant at az agyan az aszfalt mint a gondolat, hogy feltegye a kezet.
Persze egy jol megirt cikkel engem is meg lehet gyozni, es ennek meg a weblabor szerkesztok is orulnenek;) (tudod az ARC plakatrol a csajnak is ezt mondtak, aki a felso legutjabol probalta meg eltavolitani azt a furcsa allagu szerves anyagot.;))
pp
Teljesen egyetertek a tulzott
hat akkor lovagoljunk, ha mar
1. @ a hibajelzes elnyomasara jo semmi masra -> egy kezdonek inkabb karos, mert nem fogja tudni azt, hogy miert nem fut le a ciklus.
2. Alapvetoen a $szulo valtozot kene ellenorizni, nem az sql lekerdezes eredmenyet. Tehat a cikk iroja nyugodtan mondhatja, hogy figyeljen erre az, aki a fuggvenyt hasznalja. (persze mondhatja idegesen is;))
3. A result hianyabol fakado hibauzenetek tipikusan olyanok, hogy nincs tabla, mezo, hibas az sql lekerdezes stb, szoval olyanok amik csak a fejlesztes soran jonnek elo (-> ergo latni kell oket.) Addig kell maszirozni a dolgot, amig el nem tunnek ezek a hibak, tehat addig amig "nem lehet hibas a lekerdezes" allapotot el nem erjuk.
4. A sok helyen latott "hibakezeles":
'WHERE szulo="'.$szulo.'";') or die('hiba a lekerdezes soran');
szerintem dilettans megoldas, megis ezt tanitjak a kezdoknek, ugye nem erre gondoltal;))
5. az, hogy Pistike nulla tudassal bevallal egy olyan munkat, amely kepessegeit joval meghaladja, es eloallit "valamit ami mukodik" nem elitelendo. (vagy itt csak olyanok vannak, akik sose vallaltak be semmi olyat amihez nem ertettek szaz szazalekossan?)
6. az, hogy sok esetben kizarolag az ar az egyetlen szempont amikor webmestert valasztanak a vevok, se nem a cikk irojanak, se nem a "kezdoknek" (avagy kontaroknak) a hibaja.
<lorolle />
Tenyleg nem lehetne egysegesiteni a neveket? Tehat vagy "szulo" helyett "parent", vagy a "DisplayChildren" helyett valami magyar, mert ez a kavar tenyleg zavaro.
pp
Egy sor...
Persze még nagyon sok mindenbe bele lehetne kötni, de minek. A cikk aról szól, hogy hogyan kell ilyen fákat kezelni elméletben.
De mondom, várjátok meg a cikk 2. részét, attól majd mindenki dob egy hátast.
azabaj
A fuggveny neve DisplayChildren (mutasd a kölyköket;)), es tokeletesen mukodik, mert ha nincs egy talalat se, akkor nem ir ki semmit sem.
En ugyan azt mondom amit Te, hogy a cikk nem arrol szol, hogy hogyan keszitsuk fel minden eshetosegre a fuggvenyeinket, hanem a hierarchikus adatkezelesrol ;)
Reszemrol erre reagaltam:
"Ha ez a cikk fokent a kezdoknek szol, akkor nem irunk ilyen pelda kodot, hogy"
A programozas nem ping-pong, ahhol egy rosszul rogzult mozdulatot evekik tart kijavitani. Amikor programozik az ember, es talal valahogy egy jobb megoldast/modszert, akkor automatikusan azt kezdi el hasznalni, es nem kell leszoknia a regirol, mert azt kb 2-3 het alatt el is felejti;))
pp
Hierarchikus adatkezelés SQL-lel PHP-ben
hali
Hogy is van ez.
Levél, vagy ág áthelyezésekor elég csak a szülőt módosítani.
Törlésnél meg kell vizsgálni, hogy az adott elemnek vannak-e gyerekei. ha vannak, akkor szolni kell, hogy nana.
Nagyjából
--
[ Dönci ]
Igen. Pontosan azok az egysze
hali
varjuk ki 2. reszt
Remelem a szerzo epito jellegu kritikanak fogja fel az itt elhangzottakat es nem ment el a kedve a cikk irastol :)
En csak biztatni szeretnem, hogy hajra!
nem ment el a kedvem
Nem ment el a kedvem a cikk folytatásától, inkább látom hogy sokakat érdekel a problémakör, sőt még a php levlistára is valahogy beszivárgott ez a cikk, tőlem függetlenül. Szóval mivel van rá igény, és én is fejlődni akarok cikkírás tekintetében is, remélhetőleg még Karácsony előtt, ha nem, akkor a két ünnep között mindenképpen elkészítem a cikk második felét.
Janonak igaza van. Nem egyszerű cikket írni, mindenre oda kell figyelni, és úgy kell leírni, ami az ember fejében van, hogy azok is megértsék, akik aktuálisan nem foglalkoznak a problémakörrel.
Magát a kódot és az elképzelést is pofozgatni kell, és legközelebb olyan cikkel akarok előállni, amit tényleg többször átgondoltam, átolvastam, hogy minden esetleges hibát kigyomláltam már belőle. Sajna ez így sikerült, ritkán jön össze elsőre próbálkozásra tökéletes eredmény.
Ha más is kedvet érez ezek után, hogy cikket írjon, szívesen segítek is neki, mert kezdem átlátni a buktatóak, szóval senki se hátráljon meg.
Főleg mivel nem csak php és SQL témakörben szeretnék majd cikket írni, hanem majd Flash kapcsán is, elvégre kezd egyre jobban beszűrődni a dinamikus tartalmak közé a Flash, egyszerűségével, szépségével és hordozhatóságával.
--------
Poetro
További anyagok
Storing Hierarchical Data in a Database
Én a 2. oldalon részletezett mechanizmust érdekesnek találtam, bár lehet, hogy a dolog csak nekem volt akkor új.
NP
Ejnye-bejnye
dirListázó
van benne egy alapkonténer abba kerülnek a könyvtárak egymáshoz a fastruktúrának megfelelően parentId-vel kapcsolja őket (szintén rekurzió) a végén pedig meghatja a PEAR-es treeToMenu objektumot (a megfelelő belső konverzió után clsContDir:treeToMenu)
http://projektm.uw.hu/tutorial/dirTree.ZIP (paraméterezni az elejét és a végét kell)
http://pear.php.net/package/HTML_TreeMenu
a későbiekben aztán lett ennek folytatása ami egy tetszőleges könyvtárstuktúrát a megfelelő metainfo-kal elhelyez 2 táblába de az már egy teljes cikk lenne :)
úgy egyáltalán az egész értelme
1. ) Hasznos-e?
A menü vagy fa szerkesztésére külön felület vagy interface kell, ha adatbázisba tesszük.
Ennél jobbnak és közvetlenebbül felhasználhatónak tartom az xml-t. (Adatbázisba begyurmászását, plusz lépésnek) egy menü esetén. Ami többnyire design elem is. XSLT remekül alkalmazható.
2.)
van-e értelme állandóan fákat lekérdeznünk és tárolgatnunk.
Ha jól emlékszem nem jó tervezési elv egy táblának saját magára tartalmaznia mutatókat. ( mert be kell járnunk az egészet. többnyire rekurzívan. és erre nem csak az igen fejletlen MySQL esetében nem létezik intelligens megoldás.)
3.)
még a végén ezek alapján valami hatalmas fát rakok össze. ami relációs adatbázisnál kellemetlenül érint. Tekintve, hogy pont a sokszoros függést próbálom elkerülni a normalizálás során. Ezt a lépést technológiai visszafejlődésnek érzem.
A menüt állandóan így kirakni szerintem kicsit gáz.
felületről beszélsz
pontosan ezt mondtam. a krit
a kritikám negatív a cikkel kapcsolatban.
Alapok
-boogie-
mi az értelme... az XML-es megoldásnak???
Írtad:
"A menü vagy fa szerkesztésére külön felület vagy interface kell, ha adatbázisba tesszük. Ennél jobbnak és közvetlenebbül felhasználhatónak tartom az xml-t."
Kérdésem:
Milyen közvetlen interfésszel (ami mindenki gépén fennt van, nem arra gondolok pl. h "töltsön le és tanuljon meg egy XML szerkesztőt"-re gondolok; mert a brózerekben (IE) csak "nyitogatni-csukogatni" lehet a megjelenített XML-t) tudja az átlag felhasználó SZERKESZTENI pl egy XML-ben tárolt fa-szerkezetű adatbázist (fa-szerkezet pl: fotógaléria kategorizálásához használom, amit egy adminon szerkeszt az "átlag felhasználó").
(Mindenhol ez az XML "majmolást" látom(ez durván hangzik, de mint elmélet), Valaki mondja meg h miért jó minden nap új szabványt alkotni valamire, ami már megoldott? Ez is a "platformharc" része??? Mostanában ezen gondolkodom. Mert ha tényleg jó dolog, akkor én is szeretném használni.)
Pistván - karist##kukac##citromail.hu
közvetlen interfész
Nem tudok ilyen interfészt
De pont ezért kételkedem az XML-ben, hogy az miért jobb, mert ahoz sincs semmi felület, de legaláb bonylítja az életet. Vagy rosszul látom? Nos erre kéne nekem okos válasz.
Mert ha már XML, akkor miért nem lehetett már egyből a böngészőkbe egy "alap" interfészt integrálni(ami nem csak csiki-csuki módon jeleníti meg szerencsétlen XML-t), hamár úgyis sok helyen használják és szabványosított dologról van szó, hogy tényleg használ6ó legyen.
Mert csak hallom hogy vagány dolog, de miért???? Egy újabb szabvány??? Elegem kezd lenni abból, h minden nap újabb szabványt kéne megtanulni, ami végtére nem is segít, hanem csak nő a "bürokrácia".
KarIst.
faszerkezet
Nem kell megtanulni az XML-t, ha nem akarod használni, és nem gondolod, hogy jobb. Az, hogy adott feladatra mi az alkalmasabb, te döntheted el, ha más körülmények nem befolyásolnak. De ez a téma túlmutat a hierarchikus adatkezelés keretein, egy másik fórum témában kellene megvitatni.
Kapcsolódó dokumentum
--
slink
re: Kapcsolódó dokumentum
--------
Poetro
POETRO? != LOPÁS
http://www.sitepoint.com/article/hierarchical-data-database
Hm.
Minden olvasónktól elnézést kérünk a történtekért! Igyekszünk mindent megtenni annak érdekében hogy a jövőben hasonló eset ne fordulhasson elő.
Korrekt
<Nincs cím>
Az ilyet nem kellene megengedni.
honnan?
2. Honnan másolta a szerző a második részt szerinted?
Nincs
-boogie-
Hierarchia - Sorrend - NemRekurzív megvalósítás