Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Jak najoptymalniej wykonac zapytanie SQL
deirathe
post
Post #1





Grupa: Zarejestrowani
Postów: 426
Pomógł: 32
Dołączył: 24.05.2007

Ostrzeżenie: (0%)
-----


Powiedzmy ze mam tabele kategorie a w niej pola id i parent
id|parent
1 |0
2 |1
3 |1
4 |2
5 |4
6 |4
7 |5

no i powiedzmy ze pobralem element o id 7, jak najlepiej wykonac zapytanie zeby zwrocilo mi wszystkich rodzicow w poprawnej kolejnosci, tj

5,4,2,1
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 11)
Indeo
post
Post #2





Grupa: Zarejestrowani
Postów: 295
Pomógł: 7
Dołączył: 26.03.2004
Skąd: Opole

Ostrzeżenie: (0%)
-----


To ciekawe zagadnienie topologiczne i przykład jak w małej prostej tabeli można zapisać dowolnie złożona strukturę powiązań typu - potomek-rodzic. Wbrew pozorom (jak dla mnie) wydobycie takiej sekwencji nie jest proste. Na myśl przychodzi analogia do przetwarzania dokumentów XML. Wg mnie jednym zapytaniem SQL tego nie zrobisz. Możesz napisać zapytanie, które dojdzie do pewnego poziomu, ale będzie to z góry założona liczba poziomów.
Musisz przejść przez wszystkie poziomy rekurencyjnie.
Najprościej chyba napisać pętle w php, która będzie wybierać dla danego potomka jego rodzica, w następnym przebiegu rodzica z poprzedniej pętli będzie traktować jako potomka, pobierze dla niego rodzica i tak w kółko tak długo aż zostanie spełniony warunek dotarcia "na powierzchnię" czyli parent = 0 kiedy to pętla zakończy działanie a przechwycone do pomocniczej zmiennej numery rodziców można złozyć w ostateczną "ścieżkę genealogiczną".
Mozliwe też, że cos takiego mozna zapisać w postaci procedury w samym SQL'u. Tam też można składać pętle.
Go to the top of the page
+Quote Post
SirZooro
post
Post #3





Grupa: Zarejestrowani
Postów: 243
Pomógł: 32
Dołączył: 14.06.2007

Ostrzeżenie: (0%)
-----


Poczytaj te artykuły:
Managing Hierarchical Data in MySQL
Storing Hierarchical Data in a Database
Go to the top of the page
+Quote Post
deirathe
post
Post #4





Grupa: Zarejestrowani
Postów: 426
Pomógł: 32
Dołączył: 24.05.2007

Ostrzeżenie: (0%)
-----


No wlasnie to drugie rozwiazanie jest malo optymalne bo mnoza mi sie zapytania, czego chce uniknac a pierwszy artykul nadal czytam, ale juz go chyba kiedys widzialem tylko nie mialem na to czasu, a co do pierwszego to albo musze znac ilosc zaglebien i sa one ustalone albo mam numerowanie w taki sposb zeby pobierac zakres, z tym ze to wiaze sie wtedy z duza iloscia zapytan podczas tworzenia nowej podkategorii, bo trzeba aktualizowac wiekszosc wierszy :/

Ten post edytował deirathe 23.01.2008, 17:17:18
Go to the top of the page
+Quote Post
Indeo
post
Post #5





Grupa: Zarejestrowani
Postów: 295
Pomógł: 7
Dołączył: 26.03.2004
Skąd: Opole

Ostrzeżenie: (0%)
-----


W takim razie może być jeszcze prościej. Zastanówmy sie praktycznie: skąd biorą sie kolejne wpisy w takiej hierarchicznej strukturze? Prawdopodobnie ktoś dodawał kolejne gałęzie dysponując w danym momencie wiedzą o "rodzicach" pozycji, którą właśnie tworzy (nic nie bierze sie z nikąd (IMG:http://forum.php.pl/style_emoticons/default/smile.gif) . Zatem można w tej tabeli dodać kolejne pole o nazwie path w którym zapisywalibyśmy kolejno ścieżki genealogiczne kolejnych elementów. Przykładem są systemy plików - po katalogach tez trzeba chodzić rekurencyjnie ale tabela alokacji plików na danej partycji ma gotowe powiązania co jest gdzie. Podobną rolę spełniałoby to pole w tabeli. Może wygląda to dziwnie i nieelegancko ale zauważ, że nawet gdyby trzeba było przed dodaniem każdej kolejnej pozycji w strukturze odpytać "historię rodziców" to to odpytanie odbywałoby się tylko raz dla każdego elementu! Taka ściąga (IMG:http://forum.php.pl/style_emoticons/default/winksmiley.jpg) Rzeczywiste bazy danych są czasem dalekie od tych akademickich, ale dzięki temu czasem są szybsze.
Go to the top of the page
+Quote Post
deirathe
post
Post #6





Grupa: Zarejestrowani
Postów: 426
Pomógł: 32
Dołączył: 24.05.2007

Ostrzeżenie: (0%)
-----


to jest dość dobry pomysł, ale co w wypadku gdy aktualizuje rodzica? Chyba że ścieżke zapisywać jako idgrampa/idparent/idchild , tylko wtedy jeżeli chcę poznać ich wartości musiałbym wykonywać tyle zapytań ile mam w ścieżce rodzicow dziadkow i innych przodkow
Go to the top of the page
+Quote Post
bim2
post
Post #7





Grupa: Zarejestrowani
Postów: 1 873
Pomógł: 152
Dołączył: 9.04.2006
Skąd: Berlin

Ostrzeżenie: (0%)
-----


Można spróbować pobrać to do tablicy $array[$rodzic] = $id; i rekurencją przeskakiwać to (IMG:http://forum.php.pl/style_emoticons/default/smile.gif)
Go to the top of the page
+Quote Post
deirathe
post
Post #8





Grupa: Zarejestrowani
Postów: 426
Pomógł: 32
Dołączył: 24.05.2007

Ostrzeżenie: (0%)
-----


czyli pobrać całą tabelę do tablicy?
Go to the top of the page
+Quote Post
bim2
post
Post #9





Grupa: Zarejestrowani
Postów: 1 873
Pomógł: 152
Dołączył: 9.04.2006
Skąd: Berlin

Ostrzeżenie: (0%)
-----


Tak, dziś podrzucę kod, ale teraz jest za wcześnie rano (IMG:http://forum.php.pl/style_emoticons/default/biggrin.gif)
Go to the top of the page
+Quote Post
Indeo
post
Post #10





Grupa: Zarejestrowani
Postów: 295
Pomógł: 7
Dołączył: 26.03.2004
Skąd: Opole

Ostrzeżenie: (0%)
-----


To proste w przypadku zmiany musisz mieć skrypt, który "zaktualizuje" zapisane relacje.
Lepiej raz na kilka dni odpalać mocny skrypt niż 100 000 razy inny, 100 razy szybszy, który w rzeczywistości pożre 100 000 / 100 = 1000 razy więcej zasobów.
Najlepiej aktualizować tylko od modyfikowanego "rodzica" w dół (nie trzeba wszystkiego). Będzie to wykonywane jednorazowo (przy każdej zmianie na szczeblu rodzica). Poza tym zdarzeniem wyciągnięcie relacji nie będzie wymagało ani dodatkowych pytań ani operacji w php. Można tez napisać trigger, który sam będzie pilnował aktualizacji elementów potomnych na podstawie modyfikowanego rodzica i to samoczynnie, kaskadowo w dół aż osiągnie rekordy "najmłodsze" i zakończy działanie. Myślę, że to jest wykonalne, po prostu trigger byłby przy jednej zmianie kaskadowo wyzwalany z góry na dół. To chyba najbezpieczniejszy sposób ochrony integralności danych (w połączniu z kluczami obcymi). Przy śmiganiu z danymi raz w mysql a raz w php, można coś pogubić przy wystąpieniu błędu (chyba, że sie użyje transakcji, a transakcje jak wiadomo, wymagają tabel Innodb i spowalniają prace mysql)
Go to the top of the page
+Quote Post
deirathe
post
Post #11





Grupa: Zarejestrowani
Postów: 426
Pomógł: 32
Dołączył: 24.05.2007

Ostrzeżenie: (0%)
-----


"chili", robimy sobie tabele:
id|path|name
gdzie 'path' to powiedzmy nasza sciezka skladajaca sie z #id:array{}/#id:array{}, i podczas aktualizacji rekordu pobieramy inne ktore w polu path posiadaja wyrazenie #id obecnie aktualizowanego rekordu i je aktualizujemy, czy lepiej "rąbnąć" to cronem raz na godzinę?
Co prawda podczas używania to staję się przyjazne ale podczas edycji może się zrobić toporne, ciekawi mnie jak to wygląda w innych systemach które posiadają np takie a'la ścieżki. Trzeba podejreć, jeżeli ktoś ma ciekawy skrypt z dobrą metodą to niech wrzuci, przetestujemy go (IMG:http://forum.php.pl/style_emoticons/default/smile.gif)

Ten post edytował deirathe 25.01.2008, 13:32:20
Go to the top of the page
+Quote Post
bim2
post
Post #12





Grupa: Zarejestrowani
Postów: 1 873
Pomógł: 152
Dołączył: 9.04.2006
Skąd: Berlin

Ostrzeżenie: (0%)
-----


  1. <?php
  2. public function selectCategories($iId=0, $sB4='', $sSelect = '')
  3. {
  4. if(!$this->bHeader)
  5. {
  6. $this->bHeader = true;
  7. $sSelect = '<option value="0">--SELECT--</option>';
  8.  
  9. }
  10. $this->getAction('Categories', 'parseCategories');
  11. if($iId==0) 
  12. {
  13. $sClass = 'class="glowna" ';
  14. } else {
  15. $sClass = '';
  16. }
  17.  
  18. if(!empty($this->aSelectCategories[$iId]))
  19. {
  20. foreach($this->aSelectCategories[$iId] AS $iKey => $sValue)
  21. {
  22. $sSelect = $sSelect.'<option '.$sClass.'value="'.$sValue['id'].'"';
  23. if($sValue['id']==$this->catId)
  24. {
  25. $sSelect .=' selected="selected"';
  26. }
  27. $sSelect.='>'.$sB4.$sValue['name'].'</option>';
  28.  
  29. $sSelect = $this->selectCategories($sValue['id'], $sB4.'- ', $sSelect);
  30. }
  31. }
  32. $this->sSelect = $sSelect.'<!---->';
  33. return  $sSelect;
  34. }
  35. ?>

$B4 = before, czyli co ma byc przed optionem (IMG:http://forum.php.pl/style_emoticons/default/tongue.gif) np. ----

$this->getAction('Categories', 'parseCategories'); - pobiera kategorie o danym idku

@up
Po co utrudniac sobie zycie gdy można zrobić tak jak pokazałem+cache. Jak uaktualnisz wpis usuwasz cache i juz. (IMG:http://forum.php.pl/style_emoticons/default/winksmiley.jpg)
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 24.08.2025 - 11:41