2012-03-04 2 views
9

Mam dwie tabele (kraj & kaczki), w których tabela krajów zawiera wszystkie kraje na świecie, a tabela kaczek zawiera listę kaczek z polem country_id, które zawiera link do głównego kraju.MySQL zwraca pierwszy wiersz połączonej tabeli

Próbuję uzyskać listę tylko krajów z co najmniej jedną kaczką, a przy tym jednym pasującym rekordem z tabeli kaczek dla najwyżej ocenianej kaczki w tym kraju. Do tej pory mam:

SELECT * 
FROM country c 
INNER JOIN ducks d ON c.id = d.country_id 
ORDER BY c.country ASC, d.rating DESC 

Powoduje wyświetlenie listy wszystkich kaczek, a nie tylko jednego kraju.

Byłbym wdzięczny, gdyby ktoś mógł wskazać mi właściwy kierunek. Wolę zrobić to w SQL niż osobne zapytanie dla każdego kraju, aby wyciągnąć najwyżej ocenioną kaczkę.

+2

Patrz: http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax- wiersz-na-grupę-w-sql/dla przykładów, jak to zrobić. – imm

+0

Którą kaczkę chcesz? po prostu ktoś? – dotoree

+1

@dotoree Najwyższa ocena (najwyższa kaczka.rata z zestawu) –

Odpowiedz

19
SELECT c.*, d.* 
FROM country c 
    INNER JOIN ducks d 
    ON d.id =       --- guessing the ducks Primary Key here 
     (SELECT dd.id     --- and here 
     FROM ducks dd 
     WHERE c.id = dd.country_id 
     ORDER BY dd.rating DESC 
     LIMIT 1 
     ) 

indeksu na (country_id, rating, id) dla tabeli MyISAM lub (country_id, rating) dla tabeli InnoDB, w może pomóc.

To zapytanie wyświetli tylko jeden numer duck dla każdego kraju, nawet jeśli więcej niż jeden ma tę samą ocenę. Jeśli chcesz, aby pojawiły się kaczki z oceną, użyj odpowiedzi @ imm's GROUP BY.

+0

Dziękuję, że działa doskonale –

+0

@@@@@@@@ imm's anwer też jest w porządku. –

+0

+1 Bardzo ładne. Czy można to osiągnąć bez żadnego podzapytania? –

-1

Wiele baz danych ma odpowiednik "wybierz najlepsze 10 * od ...". W mySql, składnia będzie "wybierz * od ... limit 10".

... ale ...

W tym przypadku uou naprawdę chcą "grupa przez" i "max()"!

+1

Witaj, grupa ogranicza wyniki, ale funkcja MAX() wyświetla tylko maksimum dla grupy, ale reszta wiersza zawiera dane dla pierwszy rekord znaleziony przez MySQL, a nie ten z maksymalną oceną. Oto, co do tej pory miałem: SELECT c. *, D. *, MAX (d.rating) Z kraju c WEJŚCIE DOŁĄCZ DO Kaczki d ON c.id = d.country_id GROUP BY c.country ZAMÓW PRZEZ c.country ASC, d.rating DESC' –

0

Spróbuj tego:

SELECT c.country, MAX(d.rating) AS max_rating 
FROM country c 
JOIN ducks d ON c.id = d.country_id 
GROUP BY c.id 
ORDER BY c.country ASC 

Jeśli "najwyższy rating" wynosi 1, a następnie zmienić MAX(d.rating) do MIN(d.rating)

+0

Witam, to bardzo blisko, ponieważ zwraca pojedynczy kraj z maksymalną oceną, próbuję również zwrócić rekord, który odpowiada tej maksymalnej ocenie. np. jeśli zmienię pierwszy wiersz twojego kodu na 'SELECT c.country, d.id, d.rating, MAX (d.rating)' to d.rating nie zawsze jest równe MAX (d.rating) jeśli to czyni sens –

+0

Tak, robi. Zaktualizowałem odpowiedź. Proszę spróbuj ponownie. –

+0

@ J.Bruni: 'HAVING' po' ORDER BY' nie jest prawidłową składnią. –

3

Można spróbować:

SELECT c.*, d.* 
FROM country c 
INNER JOIN (
    SELECT d.country_id, d.id, MAX(d.rating) AS rating 
    FROM ducks d 
    GROUP BY d.country_id 
) q ON (q.country_id = c.id) 

INNER JOIN ducks d 
    ON (d.country_id, d.rating) = (q.country_id, q.rating) 
+0

To wymaga tylko jeszcze jednego sprzężenia, aby pokazać szczegóły dotyczące kaczek: 'INNER JOIN kaczki d ON (d.country_id, d.rating) = (q.country_id, q.rating)' –

+0

@ ypercube, true dat. – imm

8

Można spróbować po prostu dodanie wybierający się przyłączyć, na

SELECT c.*, d.* 
FROM country c 
INNER JOIN ducks d ON c.id = d.country_id 
LEFT JOIN ducks d2 ON d.country_id = d2.country_id AND d2.rating > d.rating 
WHERE d2.id IS NULL 
+0

Świetnie! Podoba mi się ta wersja. –

+1

I lepiej mieć "SELECT c. *, D. *". Nie trzeba uwzględniać kolumn 'd2. *' - które będą wszystkie NULL. –

+1

Ten powinien być zaakceptowaną odpowiedzią. – ScottG