Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php][mysql] wiele-do-wielu: grupowanie wyników
Forum PHP.pl > Forum > Przedszkole
lukasz_matysek
Piszę książkę telefoniczną w php, używam bazy mysql.
W bazie są trzy tabele:

wpisy, kategorie oraz tabela realizująca relację wiele-do-wielu: kategorieWpisy. W tabeli tej znajdują się ID kontaktów i kategorii.

Załóżmy, że robię selecta dla potrzeb wyświetlenia tablicy z kontaktami i kategoriami:

SELECT wpisy.nazwa, kategorie.nazwa FROM wpisy,kategorie,KategorieWpisy WHERE KategorieWpisy.idkontakt=wpisy.id AND KategorieWpisy.idkategoria=kategorie.id

czyli dostaję wynik w formie jednej tablicy z nazwami kontaktów i kategoriami, do których są przypisane. Tablicę tą obsługuję oczywiście w standardowy sposób fetch_array

Kiedy dany kontakt jest przypisany do więcej niż jednej kategorii, to wynik dotyczący danego kontaktu otrzymuję w formie dwóch wierszy, na przykład:

nazwakontaktu kategoria1
nazwakontaktu kategoria2

Chciałbym, żeby użytkownik zobaczył to w formie:

nazwakontaktu kategoria1,kategoria2

Problem leży w tym, że linijka "kategoria2" jest generowana już za następnym przebiegiem pętli while-mysql_fetch_array. W związku z tym nie wiem co zrobić, aby uzyskać żądany efekt.

Wycinek kodu; wynik zrzucam do zmiennej buforującej i potem wyrzucam echem.

  1. $t=mysql_query("SELECT wpisy.nazwa,kategorie.nazwa FROM KategorieWpisy,wpisy,kategorie WHERE KategorieWpisy.idwpis=wpisy.id AND KategorieWpisy.idkategoria=kategorie.id") or die (mysql_error());
  2. while($y = mysql_fetch_array($t))
  3. {
  4. $output_buffer.="<tr><td>$y[0]</td><td>$y[1]</tr>";
  5. }
mortus
Można zrobić tak
  1. $query1 = "SELECT wpisy.id AS id_wpisu, wpisy.nazwa AS nazwa_wpisu FROM wpisy";
  2. $results1 = mysql_query($query) or die(mysql_error());
  3. $output_buffer = '';
  4. while($row1 = mysql_fetch_array($result1)) {
  5. $output_buffer .= $row1['nazwa_wpisu'] . ' (';
  6. $query2 = "SELECT kategorie.nazwa AS nazwa_kategorii FROM kategorie LEFT JOIN KategorieWpisy ON KategorieWpisy.idkategoria=kategorie.id WHERE KategorieWpisy.idwpisu={$row1['id_wpisu']}";
  7. $results2 = mysql_query($query2) or die(mysql_error());
  8. $control = 0;
  9. while($row2 = mysql_fetch_array($results2)) {
  10. $output_buffer .= $row2['nazwa_kategorii'];
  11. if($control < (mysql_num_rows() - 1) {
  12. $output_buffer .= ', ';
  13. }
  14. $control++;
  15. }
  16. }
  17. $output_buffer .= ')';


Choć nie wiem, czy będzie to optymalne (najszybsze) rozwiązanie.

Opcjonalnie to co Ty dostajesz w zapytaniu możesz wrzucić do tablicy (array) i później przetwarzać.
  1. while($y = mysql_fetch_array($t)) {
  2. $wpisy[$y[0]] = $y[1];
  3. }
i sprawdź sobie co wypluje
  1. echo '<pre>';
  2. print_r($wpisy);
  3. echo '</pre>';
a będziesz wiedział, jak to "ugryźć".

EDIT: Poprawiłem kod.
@down: ma być tak jak myślisz.
lukasz_matysek
Z tego co widzę, proponujesz osobno pozyskiwać kolejne nazwy wpisów, a potem doklejać do tego w zmiennej buforującej wyszukane nazwy kategorii.

w związku z tym _prawdopodobnie_ wiersz 4 powinien wyglądać tak:
  1. while($row1 = mysql_fetch_array($results1)) {

albo się mylę. Popraw mnie jeżeli źle to rozumiem.

Pomysł jak najbardziej logiczny i bardzo mi się podoba, chociaż zwielokrotnia to ilość wykonanych zapytań i z pewnością nie jest, jak sam powiedziałeś, najbardziej optymalnym rozwiązaniem. Mimo to książka, którą piszę będzie używana na maksymalnie 10 stanowiskach w sieci lokalnej i to rzadko jednocześnie, więc temat wydajności mogę lżej potraktować.

Tak jak pisałem, ta koncepcja bardzo mi się podoba i pewnie z niej skorzystam. Jednak zainteresował mnie też drugi pomysł - zrzucenie całego wyniku do tablicy, przetworzenie jej i wyrzucenie na ekran. Mam w związku z tym pomysłem pytanie o wydajność po stronie serwera: załóżmy większe obciążenie bazy, rzędu kilkaset klientów klikających po książce w której jest kilkaset rekordów. Co się dzieje z ramem (-lub cache'm - nie wiem smile.gif ) na serwerze, kiedy serwer jest zmuszony przechowywać tak duże zmienne tablicowe?

Tal czy inaczej, dzięki za pomoc, twój post rozwiązał problem.
mortus
Oczywiście trzeba się zastanowić nad sensownym mechanizmem cache'owania takiej dużej tablicy, bo po co ją setki razy generować. Kilkaset wpisów, to raczej nie jest problem (choć to zależy przede wszystkim od "mocy" serwera), problemem będzie kilka tysięcy wpisów. Zauważ tylko, że już przy kilkuset wpisach koniecznością staje się stworzenie stronicowania, bo weź wyświetl kilkaset wpisów jednym ciągiem. A wykorzystując mechanizm stronicowania nie musimy generować, aż tak dużych tablic (podobnie przetwarzanie zapytań do bazy danych nie będzie już "tak nieoptymalne").
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.