Stocarea de arbori în baze de date relaționale
Destul de des se întâmplă ca să trebuiască să stocăm informații aflate sub formă de arbori (ex. posturi de pe un forum) într-o bază de date. Problema este că majoritatea bazelor de date sunt liniare și trebuie să transformăm informațiile noastre într-o variantă liniară.
Să considerăm că avem următorul arbore cu utilizatori, grupați în diferite categorii:
O metodă naivă de stocare ar fi să stocăm lângă fiecare nod și părintele său. Astfel, în tabelul users am avea:
id user parent
Problema este că pentru a obține arborele din baza de date, trebuie să apelăm recursiv un query către baza de date, ceea ce nu îi bine deoarece unul din cele mai mari blocaje într-o aplicație (web) este legătura cu baza de date.
În cazul nostru am obține următorul tabel:
id user left right
Pare mai complicat la prima vedere, dar este mai ușor de manipulat. O proprietate care se observă este că nodurile descendente au întotdeauna marginile cuprinse între valorile marginilor nodului părinte.
Pentru a obține ancestorii unui anumit nod, folosim următoarea comandă MySQL:
SELECT user FROM users WHERE left < (SELECT left FROM users WHERE user = 'rolisz' ) AND right > (SELECT right FROM users WHERE user = 'rolisz') ORDER BY left
Această comandă ne returna 3 rânduri care conțin: Users, Mods, Admins.
Când inserăm un nod, va trebui să modificăm toate marginile care urmează după el. Pentru aceasta trebuie să știm valoarea din dreapta a nodului după care vrem să adăugăm. Să zicem că vrem să inserăm după Admins un moderator nou. Valoare din dreapta la Admins este 10.
UPDATE users SET left = left +2 WHERE left>10
UPDATE users SET right = right +2 WHERE left>10
INSERT INTO users (user, left, right) VALUES (`new_mod`, 11, 12)
Pentru a șterge facem invers, scădem 2 din marginile nodurilor care urmează.