J'ai mis à niveau mon système et ai installé MySql 5.7.9 avec php pour une application Web sur laquelle je travaille. J'ai une requête qui est créée dynamiquement, et lorsqu'elle est exécutée dans les anciennes versions de MySql, elle fonctionne bien. Depuis la mise à niveau vers la version 5.7, j'obtiens cette erreur:
L'expression n ° 1 de la liste SELECT n'est pas dans la clause GROUP BY et contient une colonne non agrégée 'support_desk.mod_users_groups.group_id' qui ne dépend pas fonctionnellement des colonnes de la clause GROUP BY; ceci est incompatible avec sql_mode = only_full_group_by
Notez la page de manuel de Mysql 5.7 sur le sujet de Modes SQL Server .
C'est la requête qui me pose problème:
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
J'ai fait quelques recherches sur le sujet, mais je ne comprends pas assez only_full_group_by
pour comprendre ce que je dois faire pour résoudre la requête. Puis-je simplement désactiver l'option only_full_group_by
ou dois-je faire autre chose?
Faites-moi savoir si vous avez besoin de plus d'informations.
Je voudrais juste ajouter group_id
au GROUP BY
.
Lorsque SELECT
ligne une colonne qui ne fait pas partie du GROUP BY
, il peut y avoir plusieurs valeurs pour cette colonne dans les groupes, mais il ne restera plus qu'un espace pour une seule valeur dans les résultats. Ainsi, la base de données généralement doit être expliquée exactement comment transformer ces valeurs multiples en une seule valeur. Généralement, cela se fait avec une fonction d'agrégation comme COUNT()
, SUM()
, MAX()
etc ... Je dis généralement car la plupart des autres systèmes de base de données populaires insistent sur ce point . Cependant, dans MySQL avant la version 5.7, le comportement par défaut était plus tolérant, car il ne se plaindrait pas et choisirait alors arbitrairement toute valeur! Il a également une fonction ANY_VALUE()
qui pourrait être utilisée comme une autre solution à cette question si vous aviez réellement besoin du même comportement qu'auparavant. Cette flexibilité a un coût, car elle n’est pas déterministe. Je ne le recommanderais donc que si vous avez une très bonne raison pour en avoir besoin. MySQL active maintenant le paramètre only_full_group_by
par défaut pour de bonnes raisons; il est donc préférable de s'y habituer et de rendre vos requêtes conformes.
Alors pourquoi ma réponse simple ci-dessus? J'ai fait quelques hypothèses:
1) le group_id
est unique. Cela semble raisonnable, il s'agit d'une "identité" après tout.
2) le group_name
est également unique. Cette hypothèse peut ne pas être raisonnable. Si ce n'est pas le cas et que vous avez des doublons group_names
et que vous suivez ensuite mon conseil d'ajouter group_id
au GROUP BY
, vous constaterez peut-être que vous obtenez maintenant plus de résultats qu'auparavant, car les groupes portant le même nom auront désormais des lignes distinctes dans les résultats. Pour moi, cela serait mieux que de masquer ces groupes de doublons car la base de données a discrètement choisi une valeur de manière arbitraire!
C'est également une bonne pratique de qualifier toutes les colonnes avec leur nom de table ou leur alias lorsqu'il y a plus d'une table impliquée ...
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
Vous pouvez essayer de désactiver le paramètre only_full_group_by
en procédant comme suit:
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 n'accepte pas NO_AUTO_CREATE_USER
et doit donc être supprimé.
vous pouvez désactiver le message d'avertissement comme expliqué dans les autres réponses ou bien comprendre ce qui se passe et le corriger.
Depuis MySQL 5.7.5, le mode SQL par défaut inclut ONLY_FULL_GROUP_BY , ce qui signifie que lorsque vous regroupez des lignes et que vous sélectionnez un élément dans ce groupe, vous devez explicitement dire quelle ligne faut-il utiliser pour cette sélection?
Mysql a besoin de savoir quelle ligne du groupe que vous recherchez, ce qui vous donne deux options
group by rect.color, rect.value
, ce qui peut être ce que vous voulez dans certains cas. Sinon, vous obtiendrez des résultats en double avec la même couleur que vous ne souhaitez peut-être pas.AVG()
MIN()
MAX()
liste complèteANY_VALUE()
si vous êtes certain que tous les résultats du groupe sont identiques. docSi vous ne souhaitez pas modifier votre requête actuelle, suivez les étapes ci-dessous -
Sudo vim /etc/mysql/my.cnf
A
pour passer en mode insertion.Copier et coller
[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
Tapez esc
pour quitter le mode de saisie
:wq
pour enregistrer et fermer vim.Sudo service mysql restart
pour redémarrer MySQL. Utilisez ANY_VALUE()
pour faire référence à la colonne non agrégée.
Depuis MySQL 5.7 docs :
Vous pouvez obtenir le même effet sans désactiver
ONLY_FULL_GROUP_BY
en utilisantANY_VALUE()
pour faire référence à la colonne non agrégée....
Cette requête peut ne pas être valide avec
ONLY_FULL_GROUP_BY
activé, car la colonne d'adresse non agrégée de la liste de sélection n'est pas nommée dans la clauseGROUP BY
:SELECT name, address, MAX(age) FROM t GROUP BY name;
...
Si vous savez que pour un ensemble de données donné, chaque valeur de nom détermine de manière unique la valeur d'adresse, l'adresse dépend effectivement du nom de la fonction. Pour dire à MySQL d'accepter la requête, vous pouvez utiliser la fonction
ANY_VALUE()
:SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;
Je vais essayer de vous expliquer en quoi consiste cette erreur.
Depuis MySQL 5.7.5, l’option ONLY_FULL_GROUP_BY
est activée par défaut.
Ainsi, conformément à la norme SQL92 et aux versions antérieures:
n'autorise pas les requêtes pour lesquelles la liste de sélection, la condition HAVING ou la liste ORDER BY font référence à des colonnes non agrégées qui ne sont ni nommées dans la clause GROUP BY ni dépendent fonctionnellement de colonnes GROUP BY (déterminées uniquement par)
( en lire plus dans la documentation )
Donc, par exemple:
SELECT * FROM `users` GROUP BY `name`;
Vous obtiendrez un message d'erreur après avoir exécuté la requête ci-dessus.
# 1055 - L'expression n ° 1 de la liste SELECT n'est pas dans la clause GROUP BY et contient la colonne non agrégée 'testsite.user.id' qui ne dépend pas fonctionnellement des colonnes de la clause GROUP BY; ceci est incompatible avec sql_mode = only_full_group_by
Pourquoi?
Étant donné que MySQL ne comprend pas exactement quelles valeurs des enregistrements groupés doivent être extraites, c’est le point.
C'EST À DIRE. Disons que vous avez ces enregistrements dans votre table users
:
Et vous exécuterez la requête invalide présentée ci-dessus.
Et vous obtiendrez l'erreur ci-dessus, car il y a 3 enregistrements portant le nom John
, et c'est Nice, mais ils ont tous des valeurs de champs email
différentes.
Ainsi, MySQL ne comprend tout simplement pas lequel de ces enregistrements doit être restitué.
Vous pouvez résoudre ce problème en modifiant simplement votre requête comme ceci:
SELECT `name` FROM `users` GROUP BY `name`
En outre, vous pouvez ajouter d'autres champs à la section SELECT, mais vous ne pouvez pas le faire, s'ils ne sont pas agrégés, mais vous pouvez utiliser une béquille (mais cela n'est pas recommandé):
SELECT ANY_VALUE(`id`), ANY_VALUE(`email`), `name` FROM `users` GROUP BY `name`
Maintenant, vous pouvez demander, pourquoi utiliser ANY_VALUE
est fortement déconseillé?
Parce que MySQL ne sait pas exactement quelle valeur d'enregistrements groupés à récupérer, et en utilisant cette fonction, vous lui demandez d'en extraire un (dans ce cas, l'email du premier enregistrement avec le nom = John a été récupéré) .
Exactement, je ne peux pas vous dire pourquoi vous voudriez que ce comportement existe.
S'il vous plaît, si vous ne me comprenez pas, apprenez-en plus sur le fonctionnement des groupes dans MySQL, c'est très simple.
Et à la fin, voici une autre requête simple, mais valide.
Si vous souhaitez interroger le nombre total d'utilisateurs en fonction de l'âge disponible, vous pouvez écrire cette requête
SELECT `age`, COUNT(`age`) FROM `users` GROUP BY `age`;
Ce qui est entièrement valide, selon les règles de MySQL.
Etc.
Il est important de comprendre en quoi consiste exactement le problème et d’écrire ensuite la solution.
J'utilise Laravel 5.3, MySQL 5.7.12, sur laravel Homestead (0.5.0, je crois)
Même après avoir explicitement défini l'édition /etc/mysql/my.cnf
afin de refléter:
[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
Je recevais toujours l'erreur.
Je devais changer config/database.php
de true
à false
:
'mysql' => [
'strict' => false, //behave like 5.6
//'strict' => true //behave like 5.7
],
Lectures complémentaires:
https://laracasts.com/discuss/channels/servers/set-set-sql-mode-on-Homesteadhttps://mattstauffer.co/blog/strict-mode- et-other-mysql-customizations-in-laravel-5-2
Si vous utilisez wamp 3.0.6 ou une version supérieure autre que la version stable 2.5, vous pourriez être confronté à ce problème. Premièrement, le problème concerne SQL. vous devez nommer les champs en conséquence. mais il existe un autre moyen de le résoudre. cliquez sur l'icône verte de wamp. mysql-> mysql settings-> sql_mode-> aucun. ou depuis la console, vous pouvez modifier les valeurs par défaut.
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';
Ajout de lignes (mention ci-dessous) dans le fichier: /etc/mysql/my.cnf
[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
Travaille bien pour moi. Version du serveur: 5.7.18-0ubuntu0.16.04.1 - (Ubuntu)
Pour Mac:
1.Copiez le fichier my-default.cnf par défaut dans /etc/my.cnf.
Sudo cp $(brew --prefix mysql)/support-files/my-default.cnf /etc/my.cnf
2.Changez sql_mode dans my.cnf en utilisant votre éditeur favori et réglez-le à ceci
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
3. Redémarrez le serveur MySQL.
mysql.server restart
Pour localhost/wampserver 3, nous pouvons définir sql-mode = user_mode pour supprimer cette erreur:
click on wamp icon -> MySql -> MySql Setting -> sql-mode -> user_mode
puis redémarrez wamp ou apache
C'est ce qui m'a aidé à comprendre l'ensemble du problème:
Et dans ce qui suit, un autre exemple de requête problématique.
Problématique:
SELECT COUNT(*) as attempts, SUM(elapsed) as elapsedtotal, userid, timestamp, questionid, answerid, SUM(correct) as correct, elapsed, ipaddress FROM `gameplay`
WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 1 DAY)
AND cookieid = #
résolu en ajoutant ceci à la fin:
GROUP BY timestamp, userid, cookieid, questionid, answerid, elapsed, ipaddress
Note: Voir le message d'erreur en PHP, il vous indique où se situe le problème.
Exemple:
Erreur de requête MySQL 1140: Dans une requête agrégée sans GROUP BY, l'expression n ° 4 de la liste SELECT contient la colonne non agrégée 'db.gameplay.timestamp'; cela est incompatible avec sql_mode = only_full_group_by - Requête: SELECT COUNT (*) en tant que tentatives, SUM (écoulé) en tant que écoulé, total, userid, timestamp, questionid, answerid, SUM (correct), correct, écoulé, adresse IP du jeu WHERE timestamp> = DATE_SUB (NOW (), INTERVAL 1 JOUR) ET userid = 1
Dans ce cas, l'expression # 4 était manquante dans GROUP BY.
Vous pouvez ajouter un unique index
à group_id
; si vous êtes sûr que group_id
est unique.
Cela peut résoudre votre cas sans modifier la requête.
Une réponse tardive, mais cela n’a pas encore été mentionné dans les réponses. Peut-être faudrait-il compléter les réponses déjà complètes disponibles. Au moins, mon cas a été résolu lorsque j'ai dû diviser une table avec trop de champs.
Si vous rencontrez cette erreur avec Symfony avec constructeur de requêtes de doctrine, et si cette erreur est provoquée par un orderBy:
Faites attention à select
la colonne que vous voulez groupBy
et utilisez addGroupBy
à la place de groupBy
:
$query = $this->createQueryBuilder('smth')->addGroupBy('smth.mycolumn');
Fonctionne sur Symfony -
Toutes mes excuses pour ne pas utiliser votre code SQL exact
J'ai utilisé cette requête pour surmonter l'avertissement Mysql.
SELECT count(*) AS cnt, `regions_id`
FROM regionables
WHERE `regionable_id` = '115' OR `regionable_id` = '714'
GROUP BY `regions_id`
HAVING cnt > 1
note la clé pour moi être
count(*) AS cnt