n + 1 - jak pobrać dane powiązanych rekordów w jednym zapytaniu

0

Mamy takie tabele:
transaction - tabela z transakcjami
transaction_share - w jednej transakcji może brać udział kilku klientów i mają różny udział np. 60:40
contact - dane klientów

Potrzebuję wyświetlić listę transakcji, przy czym w jednej komórce potrzebuję wyświetlić listę klientów biorących w niej udział. Czyli potrzebuję imię i nazwisko oraz id klienta (do podlinkowania). Z oczywistych przyczyn nie mogę w pętli pobierać osobno danych klienta. Moje okrojone zapytanie wygląda tak:

SELECT t.id, clients
FROM transaction as t
INNER JOIN
(
  SELECT
    ts.transaction_id,
    GROUP_CONCAT(CONCAT(IFNULL(c.last_name, ''), ' ', IFNULL(c.first_name, ''))) AS clients
  FROM transaction_share AS ts
    LEFT JOIN contact AS c ON c.contact_id = ts.contact_id
  WHERE ts.deleted != 1
  GROUP BY ts.transaction_id
) AS ts ON ts.transaction_id = t.id

Oczywiście pobiera ono samo imię i nazwisko i to oddzielone przecinkami. Do tej pory nie było problemu, bo wyświetlenie wartości clients wystarczyło. Problem się pojawił, ponieważ musze każdego klienta podlinkowac.

Jedynym rozwiązaniem jakie widzę jest dodanie do CONCAT id klienta i później zrobienie explode w widoku

GROUP_CONCAT(CONCAT(c.contact_id, ':', IFNULL(c.last_name, ''), ' ', IFNULL(c.first_name, '')))

po przecinku - żeby dostać pojedyńczego klienta - oraz po dwukropku - żeby dostać atrybuty danego klienta w formie tablicy.
Wydaje mi się to bardzo brzydkie rozwiązanie. Czy jest jakieś inne?

0
Desu napisał(a):

Z oczywistych przyczyn nie mogę w pętli pobierać osobno danych klienta.

a jakież to są te oczywiste przyczyny?

Co byś nie robił to musisz odpytać transakcję a potem kontrahentów o dane. I tu nie a zmiłuj. Kwestia tylko czy chce Ci się bawić po stronie php z dzieleniem/porządkowaniem tego czy zamiast tego do każdej transakcji po prostu zapytać o kontrahentów. Jak nie chcesz mieć x+1 zapytań (gdzie x to ilość transakcji) to zrób 2 - jedno dla transakcji a drugie dla klientów, którzy biorą udział w tych transakcjach i dopasuj klienta do danej transakcji po stronie php.

0

@abrakadaber przyznam, że nie bardzo rozumiem Twój post.

a jakież to są te oczywiste przyczyny?

Co byś nie robił to musisz odpytać transakcję a potem kontrahentów o dane

Tą część odbieram jako by pobieranie dodatkowych danych w pętli było czymś normalnym, a przecież stan rzeczy na dzisiaj rano był taki, że podstrona z nieco ponad 200 transakcjami generowała ponad 11k zapytań, bo ktoś pobierał najpierw transakcje, później osobno przyległości do transakcji, klientów i ich dane i kilka innych śmieci, jak np. tabele słownikowe (tak, w pętli). Oczywiście tutaj ktoś zaczarował w drugą stronę (nawet nie wiem skąd tyle zapytań bo ctrl + a i del), ale tak czy siak byłoby tego pewnie koło tysiąca. Ja z tego zrobiłem jedno zapytanie, które wyciąga dokładnie to samo i działa sto razy szybciej.

Koniec końców musiałem kleić jsona za pomocą GROUP_CONCAT bo niestety mysql w wersji 5.6.22 jeszcze go nie wspiera, ale cały czas to JSON, więc dzięki @Panczo.

0

przy 200 transakcjach powinno być 201 zapytań maksymalnie (właśnie to dla mnie jest normalnością), każda większa ilość wskazuje na to, że zatrudniliście studentów zamiast programistów. Bo nikt normalny nie wpadłby na to aby każdą pozycję (kontrahenta) pobierać osobnym zapytaniem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1