Metoda IV

Pomysł tej metody jest bardzo podobny a nawet bym powiedział powstał na bazie skryptu umieszczonego na stronie www.depesz.com. Metoda ta opiera się na konstrukcji dwóch tabel. W pierwszej (tree) będziemy przechowywać wszystkie parametry powiązane z poszczególnymi kategoriami. Przykładowo zamieszczę w niej tylko nazwę. W drugiej zaś (tree_pos) przechowywane będą powiązania pomiędzy poszczegółnymi elementami (jeżeli oczywiście takowe istnieją). Oto przykład struktury dla tej metody:

CREATE TABLE tree (
id SERIAL PRIMARY KEY,
nazwa VARCHAR(128) NOT NULL
);
CREATE TABLE tree_pos (
id SERIAL PRIMARY KEY,
tree_id INTEGER NOT NULL,
parent_id INTEGER NOT NULL,
depth INTEGER NOT NULL
);

W stosunku do rozwiązania na stronie www.depesz.com moja metoda różni się tym że w tabeli tree dodałem pole tree_id któe to może być null:

ALTER TABLE tree ADD COLUMN tree_id INTEGER;
ALTER TABLE tree ADD CONSTRAINT fk_tree_id FOREIGN KEY (tree_id) REFERENCES tree(id);

tree_db_400Oczywiście tak jak to opisuje autor rozwiązania, metoda ta posiada minus taki, że w tabeli tree_pos przechowywane są informacje nadmiarowe. Jednak ich nadmiarowość przekłada się na wydajność i możliwości. Implementacja przenoszenia elementów pomiędzy kategoriami może się okazać zbyt skomplikowana. Doświadczyłem tego podczas implementacji tego rozwiązania. W związku z tym aby sobie trochę pomóc dodałem jeszcze jedno pole w tabeli tree w któym będę przechowywał id rodzica. Dzięki temu bez problemu mogę na tabeli tree_pos dokonywać wszelkich operacji UPDATE i DELETE zachowując informacje o konstrukcji drzewa.

Zaletą tego rozwiązania jest prostota w implementacji. Możemy tutaj bardzo szybko wyszukiwać kategorie o zadanym poziomie zagnieżdżenia. Banalne jest rónież wyświetlanie ścieżki. Łatwo można wyszukiwać elementy podpięte do kategorii na dowolnym poziomie jak rónież szybko odnaleźć rodzica z dowolnego poziomu. Skomplikowane jak się może okazać jest jedynie przenoszenie elementów. Jednakże z pomocą kilku procedur jakie napisałem w PLPGSQL`u może się okazać wprost trywialne.

No dobrze a teraz będę się tłumaczył z konstrukcji zastosowania tej metody.

W metodzie tej struktura naszego drzewa przechowywana będzie w następujący sposób:

test=# select * from tree;
id | nazwa | tree_id
----+------------------+---------
1 | Kategoria główna |
2 | Kat 1 | 1
3 | Kat 1.1 | 2
4 | Kat 1.2 | 2
5 | Kat 2 | 1
6 | Kat 2.1 | 5
7 | Kat 2.2 | 5
8 | Kat 2.3 | 5
9 | Kat 2.1.1 | 6
10 | Kat 2.1.2 | 6
11 | Kat 3 | 1
(11 rows)
test=# select * from tree_pos;
id | tree_id | parent_id | depth
----+---------+-----------+-------
3 | 1 | 1 | 0
4 | 2 | 2 | 0
5 | 2 | 1 | 1
6 | 3 | 3 | 0
7 | 3 | 2 | 1
8 | 3 | 1 | 2
9 | 4 | 4 | 0
10 | 4 | 2 | 1
11 | 4 | 1 | 2
12 | 5 | 5 | 0
13 | 5 | 1 | 1
14 | 6 | 6 | 0
15 | 6 | 5 | 1
16 | 6 | 1 | 2
17 | 7 | 7 | 0
18 | 7 | 5 | 1
19 | 7 | 1 | 2
20 | 8 | 8 | 0
21 | 8 | 5 | 1
22 | 8 | 1 | 2
23 | 9 | 9 | 0
24 | 9 | 6 | 1
25 | 9 | 5 | 2
26 | 9 | 1 | 3
27 | 10 | 10 | 0
28 | 10 | 6 | 1
29 | 10 | 5 | 2
30 | 10 | 1 | 3
31 | 11 | 11 | 0
32 | 11 | 1 | 1
(30 rows)



Jak już wspomniałem w tabelce tree_pos przechowywane są informacje o powiązaniach poszczególnych elementów z ich rodzicami (również dziadkami).

Wykonując teraz zapytanie na naszej tabeli tree_pos:
select * from tree_pos where tree_id=9;
dostaniemy wszystkich rodziców elementu "Kat 2.1.1":

id | tree_id | parent_id | depth
----+---------+-----------+-------
23 | 9 | 9 | 0
24 | 9 | 6 | 1
25 | 9 | 5 | 2
26 | 9 | 1 | 3
(4 rows)

Rozbudowując nasze zapytanie do postaci:

select t.nazwa from tree t, tree_pos tp where tp.parent_id=t.id and tp.tree_id=9 order by tp.depth desc;

otrzymujemy pełną ścieżkę począwszy od głównego korzenia:

nazwa
------------------
Kategoria główna
Kat 2
Kat 2.1
Kat 2.1.1
(4 rows)

Na podstawie tych danych możemy łatwo utworzyć taką ścieżkę:
Kategoria główna » Kat 2 » Kat 2.1 » Kat 2.1.1

Wydaje mi się, że udało mi się dobrze opisać tę metodę przechowywania. Przejdźmy zatem do implementacji.