Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Zapytanie jeden do wielu - jak sprawić, by JOIN wybrał tylko jeden konkretny wiersz
Forum PHP.pl > Forum > Bazy danych > MySQL
d4ro
Witam. Mam następujący problem. Istnieją 2 tabele: osoby i statusy, przy czym połączenie między nimi jest jeden do wielu. Jest tak z uwagi na to, że w tabeli statusy zapisują się też statusy historyczne. Mam do wykonania zapytanie, które pobierze dane osoby oraz informacje o jej aktualnym statusie. Dla ustalenia uwagi:

Tabela osoby:
  • id
  • imie
  • nazwisko


Tabela statusy:
  • id
  • id_osoby
  • data_rozpoczecia
  • info1
  • info2
  • info3


Problem polega na tym, jak zmusić MySQL do wybrania tego statusu, który ja chce? A chcę taki, którego data_rozpoczęcia jest maksymalna.

Jeżeli wykonam
  1. SELECT * FROM osoby o
  2. LEFT JOIN statusy s ON o.id=s.id_osoby
, to otrzymam zdublowane rekordy.

Jeżeli wykonam
  1. SELECT * FROM osoby o
  2. LEFT JOIN statusy s ON o.id=s.id_osoby
  3. GROUP BY o.id
, to zostanie wybrany przypadkowy status (chyba najstarszy).

Jeżeli wykonam
  1. SELECT * FROM osoby o
  2. LEFT JOIN statusy s ON o.id=s.id_osoby
  3. GROUP BY o.id
  4. HAVING max(data_rozpoczecia)
, to nic się nie zmieni.

Jeżeli wykonam
  1. SELECT * FROM osoby o
  2. LEFT JOIN statusy s ON o.id=s.id_osoby
  3. GROUP BY o.id
  4. HAVING max(data_rozpoczecia)=data_rozpoczecia
, to osoba mająca wiele statusów zniknie z wyników.

Jeżeli wykonam
  1. SELECT *, max(data_rozpoczecia) FROM osoby o
  2. LEFT JOIN statusy s ON o.id=s.id_osoby
  3. GROUP BY o.id
, to otrzymam właściwą datę statusu, ale nieprawidłowe dane.

Nic więcej nie przychodzi już mi do głowy. Może ktoś wie, jak rozwiązać mój problem?
Crozin
MySQL nie obsługuje LIMIT w JOINach, ale w tym przypadku można to bardzo łatwo objeść. W tabeli ze statusami dodaj nową kolumnę "jest aktywny" o wartości 1 lub 0. Dodaj TRIGGERa, który przy dodaniu nowego rekordu zmieni istniejące 1 na 0.

Wtedy zapytanie uprości się:
  1. SELECT ... ON (o.id = s.person_id AND s.is_active = 1) ...;
d4ro
Wszystko byłoby fajnie, gdyby nie to, że tabelki są częścią sporego systemu, który został zaprojektowany, jak został i jedyna identyfikacja aktualnego statusu jest poprzez pole data_rozpoczecia. Zastanawiam się teraz nad tym, czy nie można by było zrobić wrappera na to zapytanie, żeby można było użyć WHERE'a i jak go użyć...


[Edit]


Udało mi się biggrin.gif. Rozwiązanie nie było takie oczywiste, ale Crozin, podsunąłeś mi pewien pomysł z tym AND w ONie. Pomyslałem: Gdyby tylko dało się tak prosto przenieść warunek - który to wiersz statusów ma się dołączyć - do ONa. I wpadłem na rozwiązanie, oto ono:
  1. SELECT * FROM osoby o
  2. LEFT JOIN statusy s ON s.id = (
  3. SELECT s2.id FROM statusy s2
  4. WHERE s2.id_osoby = s.id
  5. ORDER BY data_rozpoczecia DESC
  6. LIMIT 1
  7. )


Dzięki Crozin smile.gif.
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.