Έχω αναβαθμίσει το σύστημά μου και έχω εγκαταστήσει τη MySql 5.7.9 με php για μια διαδικτυακή εφαρμογή στην οποία εργάζομαι. Έχω ένα ερώτημα που δημιουργείται δυναμικά και όταν εκτελείται σε παλαιότερες εκδόσεις της MySql λειτουργεί κανονικά. Μετά την αναβάθμιση στην έκδοση 5.7 λαμβάνω αυτό το σφάλμα:
Η έκφραση #1 της λίστας SELECT δεν περιλαμβάνεται στη ρήτρα GROUP BY και περιέχει μη συγκεντρωτική στήλη 'support_desk.mod_users_groups.group_id' η οποία είναι δεν εξαρτάται λειτουργικά από τις στήλες στη ρήτρα GROUP BY- αυτό είναι ασυμβίβαστο με sql_mode=only_full_group_by
Σημειώστε τη σελίδα του εγχειριδίου για τη Mysql 5.7 σχετικά με το θέμα Server SQL Modes.
Αυτό είναι το ερώτημα που μου δημιουργεί πρόβλημα:
SELECT mod_users_groups.group_id AS 'value',
group_name AS 'text'
FROM mod_users_groups
LEFT JOIN mod_users_data ON mod_users_groups.group_id = mod_users_data.group_id
WHERE mod_users_groups.active = 1
AND mod_users_groups.department_id = 1
AND mod_users_groups.manage_work_orders = 1
AND group_name != 'root'
AND group_name != 'superuser'
GROUP BY group_name
HAVING COUNT(`user_id`) > 0
ORDER BY group_name
Έψαξα λίγο στο google για το θέμα, αλλά δεν καταλαβαίνω το only_full_group_by
αρκετά ώστε να καταλάβω τι πρέπει να κάνω για να διορθώσω το ερώτημα. Μπορώ απλά να απενεργοποιήσω την επιλογή only_full_group_by
ή υπάρχει κάτι άλλο που πρέπει να κάνω;
Ενημερώστε με αν χρειάζεστε περισσότερες πληροφορίες.
Μπορείτε να προσπαθήσετε να απενεργοποιήσετε τη ρύθμιση only_full_group_by
εκτελώντας τα εξής:
mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
Η MySQL 8 δεν δέχεται το NO_AUTO_CREATE_USER
οπότε πρέπει να αφαιρεθεί.
Θα πρόσθετα απλώς το group_id
στο GROUP BY
.
Όταν επιλέγετε μια στήλη που δεν αποτελεί μέρος της ομάδας "GROUP BY", θα μπορούσαν να υπάρχουν πολλαπλές τιμές για τη στήλη αυτή μέσα στις ομάδες, αλλά θα υπάρχει χώρος μόνο για μια τιμή στα αποτελέσματα. Έτσι, η βάση δεδομένων συνήθως πρέπει να ενημερωθεί για το πώς ακριβώς θα μετατρέψει αυτές τις πολλαπλές τιμές σε μία τιμή. Συνήθως, αυτό γίνεται με μια αθροιστική συνάρτηση όπως COUNT()
, SUM()
, MAX()
κ.λπ... Λέω συνήθως επειδή τα περισσότερα άλλα δημοφιλή συστήματα βάσεων δεδομένων επιμένουν σε αυτό. Ωστόσο, στη MySQL πριν από την έκδοση 5.7 η προεπιλεγμένη συμπεριφορά ήταν πιο επιεικής, επειδή δεν θα διαμαρτυρηθεί και στη συνέχεια θα επιλέξει αυθαίρετα οποιαδήποτε τιμή! Διαθέτει επίσης μια συνάρτηση ANY_VALUE()
η οποία θα μπορούσε να χρησιμοποιηθεί ως άλλη λύση σε αυτό το ερώτημα, αν πραγματικά χρειαζόσασταν την ίδια συμπεριφορά με πριν. Αυτή η ευελιξία έχει ένα κόστος επειδή είναι μη ντετερμινιστική, οπότε δεν θα τη συνιστούσα, εκτός αν έχετε έναν πολύ καλό λόγο που τη χρειάζεστε. Η MySQL ενεργοποιεί τώρα τη ρύθμιση only_full_group_by
από προεπιλογή για καλούς λόγους, οπότε είναι καλύτερο να τη συνηθίσετε και να κάνετε τα ερωτήματά σας να συμμορφώνονται με αυτήν.
Γιατί λοιπόν η παραπάνω απλή μου απάντηση; Έκανα μερικές υποθέσεις:
το group_id
είναι μοναδικό. Φαίνεται λογικό, είναι ένα 'ID' τελικά.
το group_name
είναι επίσης μοναδικό. Αυτό μπορεί να μην είναι και τόσο λογική υπόθεση. Αν αυτό δεν ισχύει και έχετε κάποια διπλά group_names
και στη συνέχεια ακολουθήσετε τη συμβουλή μου να προσθέσετε το group_id
στο GROUP BY
, μπορεί να διαπιστώσετε ότι τώρα θα έχετε περισσότερα αποτελέσματα από ό,τι πριν, επειδή οι ομάδες με το ίδιο όνομα θα έχουν τώρα ξεχωριστές γραμμές στα αποτελέσματα. Για μένα, αυτό θα ήταν καλύτερο από το να έχετε αυτές τις διπλές ομάδες κρυμμένες επειδή η βάση δεδομένων έχει επιλέξει ήσυχα μια τιμή αυθαίρετα!
Είναι επίσης καλή πρακτική να προσδιορίζετε όλες τις στήλες με το όνομα του πίνακα ή το ψευδώνυμό τους όταν υπάρχουν περισσότεροι από ένας πίνακες...
SELECT
g.group_id AS 'value',
g.group_name AS 'text'
FROM mod_users_groups g
LEFT JOIN mod_users_data d ON g.group_id = d.group_id
WHERE g.active = 1
AND g.department_id = 1
AND g.manage_work_orders = 1
AND g.group_name != 'root'
AND g.group_name != 'superuser'
GROUP BY
g.group_name,
g.group_id
HAVING COUNT(d.user_id) > 0
ORDER BY g.group_name
Αν δεν θέλετε να κάνετε αλλαγές στο τρέχον ερώτημά σας, τότε ακολουθήστε τα παρακάτω βήματα -
vagrant ssh στο κουτί σας
Πληκτρολογήστε: vim /etc/mysql/my.cnf`.
Μετακινηθείτε στο κάτω μέρος του αρχείου και πληκτρολογήστε A
για να εισέλθετε σε λειτουργία εισαγωγής.
Αντιγράψτε και επικολλήστε
[mysqld]
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
Πληκτρολογήστε esc
για να βγείτε από τη λειτουργία εισόδου
Πληκτρολογήστε :wq
για να αποθηκεύσετε και να κλείσετε τον vim.
Πληκτρολογήστε sudo service mysql restart
για να επανεκκινήσετε τη MySQL.