Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Zapytanie jeden do wielu - jak sprawić, by JOIN wybrał tylko jeden konkretny wiersz
d4ro
post
Post #1





Grupa: Zarejestrowani
Postów: 2
Pomógł: 0
Dołączył: 11.02.2011

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


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?
Go to the top of the page
+Quote Post
Crozin
post
Post #2





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

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


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) ...;
Go to the top of the page
+Quote Post
d4ro
post
Post #3





Grupa: Zarejestrowani
Postów: 2
Pomógł: 0
Dołączył: 11.02.2011

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


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.

Ten post edytował d4ro 11.02.2011, 17:21:34
Go to the top of the page
+Quote Post

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

 



RSS Aktualny czas: 19.08.2025 - 19:23