Poniżej przedstawiono najprostszy możliwy przykład, chociaż każde rozwiązanie powinno być w stanie skalować do dowolnej liczby n najlepszych wyników:
Biorąc pod uwagę poniższą tabelę z kolumnami osoby, grupy i wieku, w jaki sposób można uzyskać 2 najstarsze osoby w każdej grupie? (Remisy w grupach nie powinny dawać więcej wyników, ale należy podać pierwsze 2 w kolejności alfabetycznej)
+ -------- + ------- + ----- + | Osoba | Grupa | Wiek | + -------- + ------- + ----- + | Bob | 1 | 32 | | Jill | 1 | 34 | | Shawn | 1 | 42 | | Jake | 2 | 29 | | Paul | 2 | 36 | | Laura | 2 | 39 | + -------- + ------- + ----- +
Pożądany zestaw wyników:
+ -------- + ------- + ----- + | Shawn | 1 | 42 | | Jill | 1 | 34 | | Laura | 2 | 39 | | Paul | 2 | 36 | + -------- + ------- + ----- +
UWAGA: To pytanie opiera się na poprzednim - Uzyskaj rekordy z maksymalną wartością dla każdej grupy zgrupowanych wyników SQL - aby uzyskać pojedynczy górny wiersz z każdej grupy i który otrzymał świetną odpowiedź specyficzną dla MySQL od @Bohemian:
select *
from (select * from mytable order by `Group`, Age desc, Person) x
group by `Group`
Chciałbym móc to zbudować, chociaż nie wiem jak.
Odpowiedzi:
Oto jeden ze sposobów, aby to zrobić, używając
UNION ALL
(Zobacz SQL Fiddle with Demo ). Działa to z dwiema grupami, jeśli masz więcej niż dwie grupy, musisz określićgroup
liczbę i dodać zapytania dla każdejgroup
:Można to zrobić na wiele sposobów, zapoznaj się z tym artykułem, aby określić najlepszą trasę w swojej sytuacji:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
Edytować:
To może zadziałać również dla Ciebie, generuje numer wiersza dla każdego rekordu. Korzystając z przykładu z linku powyżej, zwróci to tylko te rekordy z numerem wiersza mniejszym lub równym 2:
Zobacz Demo
źródło
SELECT
(i, w rzeczywistości, czasami ocenia je poza kolejnością). Kluczem do rozwiązania jest umieszczenie wszystkich przypisań zmiennych w jednym wyrażeniu; oto przykład: stackoverflow.com/questions/38535020/… .W innych bazach danych możesz to zrobić za pomocą
ROW_NUMBER
. MySQL nie obsługuje,ROW_NUMBER
ale możesz użyć zmiennych, aby go emulować:Zobacz, jak działa online: sqlfiddle
Edytuj Właśnie zauważyłem, że bluefeet opublikował bardzo podobną odpowiedź: +1 do niego. Jednak ta odpowiedź ma dwie małe zalety:
Więc zostawię to tutaj na wypadek, gdyby mogło to komuś pomóc.
źródło
JOIN (SELECT @prev := NULL, @rn := 0) AS vars
. Rozumiem, że chodzi o zadeklarowanie pustych zmiennych, ale wydaje się to obce dla MySql.Spróbuj tego:
PRÓBNY
źródło
a.person
.Co powiesz na samodzielne łączenie:
daje mi:
Bardzo zainspirowała mnie odpowiedź Billa Karwina na wybór 10 najlepszych rekordów w każdej kategorii
Używam również SQLite, ale to powinno działać na MySQL.
Inna sprawa: w powyższym dla wygody wymieniłem
group
kolumnę nagroupname
kolumnę.Edycja :
Kontynuując komentarz OP dotyczący brakujących wyników remisu, zwiększyłem odpowiedź snuffina, aby pokazać wszystkie remisy. Oznacza to, że jeśli ostatnie są remisami, można zwrócić więcej niż 2 wiersze, jak pokazano poniżej:
daje mi:
źródło
ERROR 1242 (21000): Subquery returns more than 1 row
, prawdopodobnie z powoduGROUP BY
. KiedySELECT MIN
wykonuję tylko podzapytanie, generuje ono trzy wiersze:34, 39, 112
i tam okazuje się, że druga wartość powinna wynosić 36, a nie 39.Rozwiązanie Snuffin wydaje się dość powolne do wykonania, gdy masz wiele wierszy, a rozwiązania Mark Byers / Rick James i Bluefeet nie działają w moim środowisku (MySQL 5.6), ponieważ polecenie zlecenie jest stosowane po wykonaniu polecenia select, więc oto wariant rozwiązań Marc Byers / Rick James w celu rozwiązania tego problemu (z dodatkową zawartością wyboru):
Próbowałem podobnego zapytania na tabeli mającej 5 milionów wierszy i zwraca wynik w mniej niż 3 sekundy
źródło
LIMIT 9999999
do dowolnej tabeli pochodnej z rozszerzeniemORDER BY
. Może to zapobiecORDER BY
ignorowaniu.Sprawdź to:
SQL Fiddle: http://sqlfiddle.com/#!2/cdbb6/15
źródło
max(internal_version - 1)
- więc mniej stresu :)Jeśli inne odpowiedzi nie są wystarczająco szybkie Wypróbuj ten kod :
Wynik:
źródło
Chciałem się tym podzielić, ponieważ spędziłem dużo czasu szukając łatwego sposobu na zaimplementowanie tego w programie Java, nad którym pracuję. To nie do końca daje wynik, którego szukasz, ale jest blisko. Funkcja o nazwie mysql
GROUP_CONCAT()
działała bardzo dobrze przy określaniu liczby wyników zwracanych w każdej grupie. UżywanieLIMIT
lub inne fantazyjne sposoby próby zrobienia tegoCOUNT
nie zadziałały dla mnie. Więc jeśli chcesz zaakceptować zmodyfikowane wyjście, jest to świetne rozwiązanie. Powiedzmy, że mam tabelę o nazwie „student” z identyfikatorami uczniów, ich płcią i gpa. Powiedzmy, że chcę uzyskać najwyższe 5 gpa dla każdej płci. Wtedy mogę napisać zapytanie w ten sposóbZauważ, że parametr „5” mówi mu, ile wpisów ma zostać połączonych w każdym wierszu
A wynik wyglądałby jakoś
Możesz także zmienić
ORDER BY
zmienną i zamówić je w inny sposób. Więc gdybym miał wiek ucznia, mógłbym zamienić „gpa desc” na „age desc” i to zadziała! Możesz także dodać zmienne do grupy według instrukcji, aby uzyskać więcej kolumn w wynikach. To jest po prostu sposób, który uważam, że jest dość elastyczny i działa dobrze, jeśli nie przeszkadza ci tylko wyświetlanie wyników.źródło
W SQL Server
row_numer()
jest potężna funkcja, którą można łatwo uzyskać, jak poniżejźródło
W MySQL jest naprawdę fajna odpowiedź na ten problem - jak uzyskać N wierszy w każdej grupie
Na podstawie rozwiązania w odnośniku, do którego się odwołuje, Twoje zapytanie wyglądałoby tak:
gdzie
n
jesttop n
iyour_table
to nazwa twojego stołu.Myślę, że wyjaśnienie w dokumencie jest naprawdę jasne. Dla szybkiego odniesienia skopiuję i wkleję tutaj:
źródło