Rodzic i dziecko kategorii / typu
Jednym z elementów rozbudowanego systemu CRM, nad którym pracuje był wybór typu projektu z podziałem na główny typ oraz podtyp. Można to zrealizować poprzez stworzenie dwóch tabel (typy i podtypy połączone relacją) lub jednej (wykorzystując kolumnę, która będzie przechowywać informację o rodzicu). Oba rozwiązania mają jeden większy problem do rozwiązania, jeśli będziemy chcieli dać wybór pozycji poprzez jedno pole typu <select> trzeba to najpierw posortować. We wpisie skupię się na przykładzie z jedną tabelą.
Zanim przejdę do sedna chciałbym nadmienić, że żadnych struktur drzewiastych na taką drobnostkę nie zamierzałem stosować. Bazujemy tylko i wyłącznie na rodzicu oraz dziecku, nie ma więcej potomków i ten wpis się na tą strukturę zamyka. Kolejna uwaga to w dalszej części posłużę się przykładem bazującym na nazwach: kategoria i podkategoria bo zapewne więcej osób pod takimi nazwami będzie poszukiwać rozwiązania zagadnienia.
Stwórzmy i wypełnijmy danymi przykładową tabelę z kategoriami.
Chcielibyśmy teraz pobrać za pomocą jednego zapytania, nie musząc robić dodatkowych operacji w PHP, posortowane kategorie wraz z podkategoriami według kolumny "ordering", a następnie "name". Czyli uzyskać poniższy wynik (w nawiasach umieszczone są wartości kolumny "ordering", minusy są dodane poza sql poprzez warunek: jeśli (rodzic) dodaj minus).
CMS (10) - Joomla (1) - Drupal (2) - CMS Made Simple (3) Blog (20) - Serendipity Weblog System (10) - Wordpress (20) Forum (30) - phpBB 2 (10) - IPB (20) - phpBB 3 (20)
Wynik ten udało mi się zrealizować dwoma sposobami. Pierwsze zapytanie opiera się na odpowiednim warunku w ORDER BY.
Natomiast drugie z wykorzystaniem odpowiedniego warunku przy LEFT JOIN w klauzuli FROM.
Pozostałe rzeczy związane z rodzicem i dzieckiem nie powinny przysporzyć problemów, a są to:
- Przy usuwaniu kategorii głównej sprawdzenie czy nie posiada podkategorii
- Przy podpinaniu kategorii głównej do innej kategorii głównej sprawdzenie czy nie posiada podkategorii
Słowa kluczowe: PostgreSQL, Techblog, kategorie, podkategorie, potomek, rodzic, sql, artykuł, blog

Komentarze i opinie
Albo zdjąć obciążenie z bazy danych i sortować w kodzie programu. Wtedy do SQL masz tylko jedno zapytanie z ORDER BY parentId, ordering
BTM - prawdopodobnie baza zrobi to szybciej :) a zapytanie jest tak czy tak jedno.
@yaro: ok inaczej, zrobisz to bez podzapytań, które mogą być "a pain in the ass" przydużych bazach. Nie wiem, czy baza zrobi to szybciej - zależy od sprzętu, zależy od złożoności przypadku. Posortowanie tego potem w -dajmy na to- PHP to jeden foreach.
Nie mówię, że tu podane rozwiązanie jest w jakimkolwiek stopniu złe oczywiście. Nie bijcie :)
@BTM: na biczowanie to trzeba sobie zasłużyć ;P
rekordów będzie kilkadziesiąt więc wydajność nie ma tu żadnego znaczenia, w PHP chwilę myślałem, coś mi nie wyszło to stwierdziłem, że zrobię to przez SQL i przy okazji wpis do bloga ;)
To ja może trochę z innej beczki (z zupełnie innej ;) ). Zamiast wpisywania takich potworków: SELECT
c1.*, c2.ordering as x
FROM
"categories" c1
-- połącz kategorię z rodzicem lub jeśli jest kategorią główną to połącz z samym sobą
LEFT JOIN "categories" c2 ON(c2."categoryId" = c1."parentId"
OR (c1."parentId" = 0 AND c2."categoryId" = c1."categoryId"))
ORDER BY
c2."ordering",
c2."name",
c1."parentId",
c1."ordering",
c1."name"
zdecydowanie bardziej wole pisanie zapytań SQL dla Postgresa w formie widoku. Robię sobie widok do kilku tabel (wiem wiem to zapytanie nie jest jeszcze złożone ale i tak można zrobić widok można go później ewentualnie rozbudowywać) i w kodzie operuje już tylko na widoku i ewentualnych operacjach na nich. To tak w ramach offtopa. Przepraszam jeśli jest to kompletnie nie na temat poczułem wewnętrzną potrzebę napisania tego ;)
Sory storm ale to jest jeden z najgroszych albo i najgorszy sposob reprezentacji drzewa.
Polecam: http://articles.sitepoint.com/print/hierarchical-data-database
Następnym razem na czerwono napisze, że jest tylko jeden poziom zagłębienia ;)
Nowy komentarz