Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL]GROUP_CONCAT
Forum PHP.pl > Forum > Przedszkole
brymen
Witam,
Mam trzy tabele op, rem, users. Zapytanie zwraca mi wyniki z tabeli op oraz z tabeli rem podczepia mi id użytkowników. Potrzebuję jeszcze translatora id na name z 3 tabeli users. Jakaś podpowiedź?
SELECT `op1`.`id` AS id_op, GROUP_CONCAT(`op2`.`id`) AS `id_user` FROM `op` AS `op1` LEFT JOIN `rem` AS `op2` ON `op1`.`id` = `op2`.`id_wt` WHERE `op1`.`id` = 284
Wynik zapytania z brakującym elementem questionmark.gif
id_op | id_user | name
284 | 174,324 | questionmark.gif


Dziękuję za pomoc.
SmokAnalog
Musisz zrobić jeszcze jeden JOIN.
brymen
Próbowałem, jednak mi nie wychodzi, dlatego pytam. Zrobiłem podzapytanie na początku SELECTa bez dodatkowego JOINa i nawet działa ale jak mi sprawdza tabele które mają po 30tys rekordów to trwa to ok 5s, zdecydowanie za długo. Dlatego chciałbym zamienić to na JOINa.
SmokAnalog
Pokaż tego swojego JOIN-a to Ci powiem dlaczego Ci nie działa.
brymen
Próbowałem kilku sposobów ale raczej kupy się to nie trzyma.
Kod
SELECT `op1`.`id`, GROUP_CONCAT(`rem1`.`id`) AS `id_user`, GROUP_CONCAT(`users1`.`name`) AS `name` FROM `op` AS `op1`
LEFT JOIN `rem` AS `rem1` ON `rem1`.`id_wt` = `op1`.`id`  
LEFT JOIN `users` AS `users1` ON `users1`.id IN (GROUP_CONCAT(`rem1`.`id`))

lub wersja z podzapytaniem po JOIN
Kod
[sql]SELECT `op1`.`id`, GROUP_CONCAT(`rem1`.`id`) AS `id_user`, GROUP_CONCAT(`users1`.`name`) AS `name` FROM `op` AS `op1`
LEFT JOIN `rem` AS `rem1` ON `rem1`.`id_wt` = `op1`.`id`  
LEFT JOIN (SELECT `name` AS `usr` FROM `users`) AS `hh` ON `hh`.`id` IN (GROUP_CONCAT(`rem1`.`id`)[/sql]
trueblue
Trzeci LEFT JOIN ma łączyć pojedyncze wartości pól, czyli tam bez żadnego GROUP_CONCAT.
Sprawdź czy masz pozakładane indeksy na łączone pola, albo relacje w przypadku tabel typu InnoDB.
brymen
W trzecim LEFT JOIN faktycznie się rozpędziłem ale to nie zmienia faktu, że i tak nie działa. Indeksy mam na wszystkie wymagane kolumny jednak tylko pojedyncze. Łączone mogą znacząco przyspieszyć?
trueblue
Pokaż zapytanie ostateczne.
Co to znaczy, że nie działa?

Indeks powinien być założony tam gdzie zachodzą porównania (WHERE, JOIN).
brymen
Działające zapytanie, które chciałbym przepisać na JOIN bez podzapytania.

SELECT `op1`.`id`,(SELECT GROUP_CONCAT(`us`.`name`) FROM `users` AS `us` LEFT JOIN `rem` ON `us`.`id` = `rem`.`id_user` WHERE (`op1`.`id` = `rem`.`id_wt`) AND `us`.`id` IN (SELECT `id_user` FROM `rem` AS `r` WHERE `r`.`id_wt` = `op1`.`id`)) AS `usr` FROM `op` AS `op1`
trueblue
Myślałem, że wrócisz do dwóch LEFT JOIN.

Może bez aliasów tabel będzie czytelniej:

  1. SELECT op.id, GROUP_CONCAT(rem.id) AS id_user, GROUP_CONCAT(users.name) AS name
  2. FROM op
  3. LEFT JOIN rem ON rem.id_wt = op.id
  4. LEFT JOIN users ON users.id=rem.id
  5. WHERE op.id = 284


Dlaczego to zapytanie daje niepoprawny wynik?
brymen
Błąd znaleziony, moja wina. Nie wiem dlaczego w tabeli users brakowało id które były w tabeli rem, nie sprawdzając tego uznałem, że mam błąd w zapytaniu.

Dziękuję za pomoc.
trueblue
A zgrupowane name masz w takiej kolejności jak odpowiadające im zgrupowane id?
brymen
Tak, kolejność name pokrywa się z id ale dla mnie nie ma to już większego znaczenia. Teraz muszę sprawdzić czy całe zapytanie wykona się szybciej. Muszę jeszcze pomyśleć nad grupowymi indeksami, wcześniej nie brałem tego pod uwagę, ustawiłem pojedyncze i wszystko śmigało. Baza zaczęła się przytykać więc czas na optymalizację.

To może jeszcze mała podpowiedź. Zapytanie poniżej działa idealnie z WHERE ale potrzebowałbym wyświetlić cała tabelę z LEFT JOIN. Bez warunku podstawia mi wszystko do jednego pierwszego wiersza. Widać, że GROUP_CONCAT blokuje.

Kod
SELECT op.id, GROUP_CONCAT(rem.id) AS id_user, GROUP_CONCAT(users.name) AS name
FROM op
LEFT JOIN rem ON rem.id_wt = op.id
LEFT JOIN users ON users.id=rem.id
WHERE op.id = 284
trueblue
GROUP BY op.id zamiast WHERE.
brymen
Zamiana podzapytania na LEFT JOIN nie przyspieszyło działania. Znalazłem jednak dokładna przyczynę. Poniższy kod wykonuje się prawidłowo, jednak bardzo długo ok 5s. Przyczyną jest dodatkowy warunek w środkowym LEFT JOIN
Kod
OR `rem`.`id_wt` =  `event2`.`id
.
Mała legenda:
`mark` - kolumna grupująca
`link_id` - kolumna łącząca
`id_wt` = id z tabeli op

  1. SELECT `event`.`id`, GROUP_CONCAT(`users`.`email`) AS `user_ack` FROM `event` AS `event1`
  2.  
  3. LEFT JOIN `event` AS `event2` ON `event2`.`mark` = `event1`.`link_id` AND `event2`.`id` = (SELECT MAX(`id`) FROM `event` WHERE `mark` = `event1`.`link_id`)
  4. LEFT JOIN `rem` ON `rem`.`id_wt` = `event1`.`id` OR `rem`.`id_wt` = `event2`.`id`
  5. LEFT JOIN `users` ON `users`.`id` = `rem`.`id_user`
  6.  
  7. WHERE `event1`.`id` IN (SELECT MAX(`id`) FROM `event` GROUP BY `mark`) GROUP BY `event1`.`id`


Ma ktoś pomysł jak to lepiej napisać?
SmokAnalog
Zacznij od zmiany nazw tabel i kolumn jeśli to możliwe. Żadnych op, op1, zn, bo aż się nie chce tego czytać.
brymen
Poprawiłem nazwy kolumn, jednak nie mam pewności czy teraz jest bardziej czytelne. Aliasy event1, event2 musiały pozostać, bez tego query prawidłowo nie zadziała (chyba).
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.