Mam stolik, który wygląda jak ten wywołujący „makerar”
cname | wmname | avg
--------+-------------+------------------------
canada | zoro | 2.0000000000000000
spain | luffy | 1.00000000000000000000
spain | usopp | 5.0000000000000000
I chcę wybrać maksymalną średnią dla każdej nazwy.
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;
ale dostanę błąd,
ERROR: column "makerar.wmname" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;
więc to robię
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname, wmname;
nie przyniesie to jednak zamierzonych rezultatów i pokazano niepoprawne dane wyjściowe poniżej.
cname | wmname | max
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | luffy | 1.00000000000000000000
spain | usopp | 5.0000000000000000
Rzeczywiste wyniki powinny być
cname | wmname | max
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | usopp | 5.0000000000000000
Jak mogę rozwiązać ten problem?
Uwaga: Ta tabela to WIDOK utworzony z poprzedniej operacji.
sql
group-by
aggregate-functions
postgresql-9.1
Losowa osoba
źródło
źródło
wmname="usopp"
oczekiwany, a nie na przykładwmname="luffy"
?Odpowiedzi:
Tak, jest to częsty problem z agregacją. Przed SQL3 (1999) wybrane pola muszą pojawić się w
GROUP BY
klauzuli [*].Aby obejść ten problem, musisz obliczyć agregację w zapytaniu podrzędnym, a następnie połączyć ją ze sobą, aby uzyskać dodatkowe kolumny, które musisz pokazać:
Ale możesz także użyć funkcji okna, która wygląda na prostszą:
Jedyne w tej metodzie jest to, że pokaże wszystkie rekordy (funkcje okien nie grupują się). Ale pokaże poprawne (tj. Maksymalne na
cname
poziomie)MAX
dla kraju w każdym rzędzie, więc to zależy od ciebie:Rozwiązaniem, prawdopodobnie mniej eleganckim, aby pokazać jedyne
(cname, wmname)
krotki pasujące do wartości maksymalnej, jest:[*]: Co ciekawe, chociaż specyfikacja pozwala na wybranie niezgrupowanych pól, wydaje się, że głównym silnikom się to nie podoba. Oracle i SQLServer po prostu w ogóle na to nie pozwalają. Mysql domyślnie pozwalał na to, ale teraz od 5.7 administrator musi włączyć tę opcję (
ONLY_FULL_GROUP_BY
) ręcznie w konfiguracji serwera, aby ta funkcja była obsługiwana ...źródło
MAX
(patrz odpowiedź @ypercube, w mojej odpowiedzi jest też inne rozwiązanie), ale nie w sposób, w jaki to robisz. Sprawdź oczekiwany wynik.avg
nacname
), ale nie ogranicza wierszy wyniku (jak chce OP). Zobacz Rzeczywiste wyniki powinny być akapitem w pytaniu.ONLY_FULL_GROUP_BY
w MySQL 5.7 nie aktywuje drogę SQL standard określa, kiedy kolumny mogą być pominięte wgroup by
(albo zachowują się jak czyni MySQL PostgreSQL). Po prostu przywraca stare zachowanie, w którym MySQL zwraca losowe (= „nieokreślone”) wyniki.W Postgres możesz także użyć specjalnej
DISTINCT ON (expression)
składni:źródło
BY cname
?Problem z określaniem niezgrupowanych i niezagregowanych pól w
group by
selekcjach polega na tym, że silnik nie ma możliwości sprawdzenia, które pole rekordu powinno w tym przypadku zwrócić. Czy to pierwszy? Czy to jest ostatnie Zwykle nie ma zapisu, który naturalnie odpowiadałby wynikowi zagregowanemu (min
imax
są wyjątkami).Istnieje jednak obejście: należy również agregować wymagane pole. W posgresie powinno to działać:
Zauważ, że to tworzy tablicę wszystkich wnamesów, uporządkowaną według avg, i zwraca pierwszy element (tablice w postgresie są oparte na 1).
źródło
Korzystanie z
rank()
funkcji okna :Uwaga
Każda z nich zachowa wiele maksymalnych wartości na grupę. Jeśli chcesz mieć tylko jeden rekord na grupę, nawet jeśli jest więcej niż jeden rekord o średniej równej maksimum, powinieneś sprawdzić odpowiedź @ ypercube.
źródło
Dla mnie nie chodzi o „powszechny problem agregacji”, ale o niepoprawne zapytanie SQL. Jedną poprawną odpowiedzią dla „wybierz maksymalną średnią dla każdej nazwy ...” jest
Wynik będzie:
Ten wynik ogólnie odpowiada na pytanie „Jaki jest najlepszy wynik dla każdej grupy?” . Widzimy, że najlepszy wynik dla Hiszpanii to 5, a dla Kanady najlepszy wynik to 2. To prawda i nie ma błędu. Jeśli musimy również wyświetlić nazwę wmname , musimy odpowiedzieć na pytanie: „Jaka jest ZASADA wyboru wmname z wynikowego zestawu?” Zmieńmy trochę dane wejściowe, aby wyjaśnić błąd:
Które wynikają można się spodziewać na runnig to zapytanie:
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;
? Powinien to byćspain+luffy
lubspain+usopp
? Czemu? W zapytaniu nie jest określone, jak wybrać „lepszą” nazwę wmname, jeśli kilka jest odpowiednich, więc wynik również nie jest określony. Dlatego interpreter SQL zwraca błąd - zapytanie jest nieprawidłowe.Innymi słowy, nie ma poprawnej odpowiedzi na pytanie „Kto jest najlepszy w
spain
grupie?” . Luffy nie jest lepszy od usopp, ponieważ usopp ma ten sam „wynik”.źródło
SELECT cname, id, MAX(avg) FROM makerar GROUP BY cname;
które spowodowało ten błąd wprowadzający w błąd.To też wydaje się działać
źródło
Niedawno napotkałem ten problem, gdy próbowałem liczyć użycie
case when
, i stwierdziłem, że zmiana kolejności instrukcjiwhich
icount
rozwiązuje problem:Zamiast używać - w tym ostatnim, gdzie dostałem błędy, że jabłka i pomarańcze powinny pojawiać się w funkcjach agregujących
źródło
which
Stwierdzenie?