MySQL Error 1055 Expression #n of SELECT list is not in GROUP BY clause and contains nonaggregated column

Si vous êtes sur cette page c’est que vous avez rencontré une erreur avec la version 5.7 de MySQL ! (Je suis sous OSX Mojave, aussi cette solution est significative pour les Mac, mais aussi pour Linux)

Pourquoi avez vous cette erreur ?

Dans la version 5.7 de MySQL, lorsque vous faites une aggrégation de colonne, vous devez spécifier explicitement le nom de la colonne à aggréger dans le SELECT sinon vous aurez cette erreur. Parce que par défaut dans cette nouvelle version on interdit des GROUP BY implicite. Normalement le GROUP BY ne peut se faire que sur des noms de colonnes agrégées par une des 5 fonctions d’aggrégation suivantes : SUM, COUNT, MAX, MIN, AVERAGE .

Il y a une variable qui s’appelle sqlmode, et conditionne le fonctionnement des requêtes SQL. Par défaut sont contenu est :

ONLY_FULL_GROUP_BY,NO_AUTO_CREATE_USER,STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION

En premier on a ONLY_FULL_GROUP_BY, c’est elle qui nous intéresse. Il faut le supprimer pour vous puissiez faire des GROUP BY implicite. Qu’est-ce qu’un GROUP BY implicite? Imaginez que vous avez la requête suivante

SELECT id, username FROM user GROUP BY id

Sur la requête ci-dessus, on groupe sur la colonne id, or il n’y aucune fonction d’aggrégation. Donc ceci n’est plus permis, à moins de faire un petit réglage dans le fichier de configuration my.cnf un peu plus loin.

Voici une requête plus propre :

SELECT count(amount) AS total, customer FROM order GROUP BY total

Dans la requête ci-dessus, la colonne avec l’alias total est une colonne agrégée, donc le group by sur cette colonne est tout à fait explicite, avec la nouvelle version de MySQL elle passera sans problème. C’est d’ailleurs comme ça que j’avais appris.

Comment résoudre cette erreur ?

Dans la configuration de MySQL 5.7, il faut trouver la variable qui permet de configurer soit en runtime soit au démarrage (et ce de façon permanente) le comportement de votre base de données favorite.

La façon runtime (ne marche pas pour moi)

Vous pouvez faire cette requête dans la console MySQL pour montrer le contenu de la variable sql_mode:

SELECT @@sql_mode 
> STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

Jouez cette requête pour modifier la variable, le but étant de supprimer le ONLY_FULL_GROUP_BY et de garder le reste, je tiens à préciser que cette méthode n’a pas marché pour moi, néanmoins marche dans pour les requêtes dans MySQLWorkbench.

SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

La façon permanente

Le mieux est de modifier le fichier my.cnf, et de redémarrer MySQL. Donc éditez le fichier my.cnf qui se trouve dans /etc pour Linux et MacOS en insérant cette ligne dans la section [mysqld] :

[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

Redémarrer MySQL sur Linux (Debian, Ubuntu)

sudo /etc/init.d/mysql restart
ou
service mysqld restart

Redémarrer MySQL sur MacOS

J’ai eu plus de difficulté, en effet sur le Net, on trouve souvent cette commande :

sudo /usr/local/mysql/support-files/mysql.server restart

Si elle ne marche pas, je pense si vous avez installé MySQL avec Homebrew, il faut localiser le répertoire de MySQL, pour ma part sous Mojave il se trouve dans le répertoire /usr/local/Cellar/mysql@5.7/5.7.26/support-files/mysql.server :

sudo /usr/local/Cellar/mysql@5.7/5.7.26/support-files/mysql.server restart

Pourquoi ne pas modifier les requêtes SQL pour les mettre à jour?

C’est possible, mais vous n’avez pas forcément le temps de le faire, aussi j’ai choisi cette solution.

Note :

J’ai perdu pas mal de temps avec PDO, n’ayant pas les affichages d’erreurs, juste après la requête, vous pouvez retourner le code erreur donné par PDO, il faut absolument le faire car PDO peut planter sans broncher, et le mettre dans le bloc try ... catch ne suffit pas à lancer une PDOException (du moins dans mes réglages à moi)

$stmt = $dbh->query($sql);
$dbh->errorInfo();// tableau d'erreur très utile !
Retour en haut