Περισσότερα
πρέπει να εμφανίζεται στη ρήτρα GROUP BY ή να χρησιμοποιείται σε μια αθροιστική συνάρτηση
Έχω έναν πίνακα που μοιάζει με τον ακόλουθο καλούντα 'makerar',
cname | wmname | avg
--------+-------------+------------------------
canada | zoro | 2.0000000000000000
spain | luffy | 1.00000000000000000000
spain | usopp | 5.0000000000000000
Και θέλω να επιλέξω το μέγιστο μέσο όρο για κάθε cname.
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;
αλλά θα λάβω ένα σφάλμα,
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;
έτσι κάνω αυτό
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname, wmname;
ωστόσο αυτό δεν θα δώσει τα επιθυμητά αποτελέσματα και εμφανίζεται η λανθασμένη έξοδος παρακάτω.
cname | wmname | max
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | luffy | 1.00000000000000000000
spain | usopp | 5.0000000000000000
Τα πραγματικά αποτελέσματα πρέπει να είναι
cname | wmname | max
--------+--------+------------------------
canada | zoro | 2.0000000000000000
spain | usopp | 5.0000000000000000
Πώς μπορώ να διορθώσω αυτό το πρόβλημα;
Σημείωση: Αυτός ο πίνακας είναι ένα VIEW που δημιουργήθηκε από μια προηγούμενη λειτουργία.
239
3
Ναι, αυτό είναι ένα συνηθισμένο πρόβλημα συνάθροισης. Πριν από την SQL3 (1999), τα επιλεγμένα πεδία πρέπει να εμφανίζονται στη ρήτρα
GROUP BY
[*].Για να παρακάμψετε αυτό το πρόβλημα, πρέπει να υπολογίσετε τη συνάθροιση σε ένα υποερώτημα και στη συνέχεια να την ενώσετε με τον εαυτό της για να λάβετε τις πρόσθετες στήλες που θα πρέπει να εμφανίσετε:
Αλλά μπορείτε επίσης να χρησιμοποιήσετε τις συναρτήσεις παραθύρου, οι οποίες φαίνονται απλούστερες:
Το μόνο πράγμα με αυτή τη μέθοδο είναι ότι θα εμφανίσει όλες τις εγγραφές (οι συναρτήσεις παραθύρου δεν ομαδοποιούν). Αλλά θα δείξει το σωστό (δηλ. μεγιστοποιημένο σε επίπεδο
cname
)MAX
για τη χώρα σε κάθε γραμμή, οπότε εξαρτάται από εσάς:Η λύση, αναμφισβήτητα λιγότερο κομψή, για να δείξετε μόνο τις πλειάδες
(cname, wmname)
που ταιριάζουν με την τιμή max, είναι:[*]: Ενδιαφέρον είναι ότι, παρόλο που οι προδιαγραφές επιτρέπουν την επιλογή μη ομαδοποιημένων πεδίων, οι μεγάλες μηχανές δεν φαίνεται να το συμπαθούν ιδιαίτερα. Η Oracle και ο SQLServer απλά δεν το επιτρέπουν καθόλου. Η Mysql συνήθιζε να το επιτρέπει από προεπιλογή, αλλά τώρα από την έκδοση 5.7 ο διαχειριστής πρέπει να ενεργοποιήσει αυτή την επιλογή (
ONLY_FULL_GROUP_BY
) χειροκίνητα στη διαμόρφωση του διακομιστή για να υποστηρίζεται αυτή η λειτουργία...Στο Postgres, μπορείτε επίσης να χρησιμοποιήσετε την ειδική σύνταξη
DISTINCT ON (expression)
:Χρήση της συνάρτησης
rank()
window function:Σημείωση
Οποιοδήποτε από τα δύο θα διατηρήσει πολλαπλές μέγιστες τιμές ανά ομάδα. Αν θέλετε μόνο μία εγγραφή ανά ομάδα ακόμα και αν υπάρχουν περισσότερες από μία εγγραφές με avg ίσο με max θα πρέπει να ελέγξετε την απάντηση του @ypercube's.