les - sql sum group by




Comportement GROUP BY lorsqu'aucune fonction d'agrégat n'est présente dans la clause SELECT (6)

J'ai une table emp avec la structure et les données suivantes:

name   dept    salary
-----  -----   -----
Jack   a       2
Jill   a       1
Tom    b       2
Fred   b       1

Quand j'exécute le SQL suivant:

SELECT * FROM emp GROUP BY dept

J'ai le résultat suivant:

name   dept    salary
-----  -----   -----
Jill   a       1
Fred   b       1

Sur quelle base le serveur a-t-il décidé de renvoyer Jill et Fred et d'exclure Jack et Tom?

Je cours cette requête dans MySQL.

Note 1: Je sais que la requête n'a pas de sens en soi. J'essaie de déboguer un problème avec un scénario «GROUP BY». J'essaie de comprendre le comportement par défaut à cette fin.

Note 2: Je suis habitué à écrire la même clause SELECT que la clause GROUP BY (moins les champs agrégés). Quand je suis tombé sur le comportement décrit ci-dessus, j'ai commencé à me demander si je pouvais m'en remettre à des scénarios tels que: sélectionner les lignes de la table emp où le salaire est le plus bas / le plus élevé dans le rayon. Par exemple: Les instructions SQL comme ceci fonctionnent sur MySQL:

SELECT A.*, MIN(A.salary) AS min_salary FROM emp AS A GROUP BY A.dept

Je n'ai trouvé aucun matériel décrivant pourquoi un tel SQL fonctionne, plus important encore si je peux compter sur un tel comportement de manière cohérente. Si c'est un comportement fiable, alors je peux éviter les requêtes comme:

SELECT A.* FROM emp AS A WHERE A.salary = ( 
            SELECT MAX(B.salary) FROM emp B WHERE B.dept = A.dept)

Autant que je sache, pour vos besoins, les lignes spécifiques retournées peuvent être considérées comme aléatoires.

La commande n'a lieu qu'après l'exécution de GROUP BY


C'est un peu tard, mais je vais le mettre en place pour référence future.

Le GROUP BY prend la première ligne qui a un doublon et rejette toutes les lignes qui correspondent après lui dans le jeu de résultats. Donc, si Jack et Tom ont le même département, celui qui apparaît le premier dans un SELECT normal sera la ligne résultante dans le GROUP BY.

Si vous voulez contrôler ce qui apparaît en premier dans la liste, vous devez faire un ORDER BY. Cependant, SQL n'autorise pas ORDER BY à venir avant GROUP BY, car il va lancer une exception. La meilleure solution de contournement pour ce problème consiste à effectuer ORDER BY dans une sous-requête et puis un GROUP BY dans la requête externe. Voici un exemple:

SELECT * FROM (SELECT * FROM emp ORDER BY name) as foo GROUP BY dept

C'est la technique la plus performante que j'ai trouvée. J'espère que ça aide quelqu'un.


Je pense que SQL ANSI exige que le select inclut uniquement les champs de la clause GROUP BY, plus les fonctions d'agrégat. Ce comportement de MySQL ressemble à renvoyer une ligne, peut-être la dernière lue par le serveur, ou n'importe quelle ligne à portée de main, mais ne comptez pas dessus.


Je trouve que la meilleure chose à faire est de considérer ce type de requête non pris en charge. Dans la plupart des autres systèmes de base de données, vous ne pouvez pas inclure de colonnes qui ne figurent ni dans la clause GROUP BY ni dans une fonction d'agrégation dans les clauses HAVING, SELECT ou ORDER BY.

Au lieu de cela, considérez que votre requête lit:

SELECT ANY(name), dept, ANY(salary)
FROM emp 
GROUP BY dept;

... puisque c'est ce qui se passe.

J'espère que cela t'aides....


Si vous regroupez par département, est-ce important pour les autres données? Je sais que Sql Server n'acceptera même pas cette requête. S'il y a une possibilité que cela sonne comme il pourrait y avoir d'autres problèmes.


Vous pouvez mettre un:

SET sql_mode = 'ONLY_FULL_GROUP_BY'

avant votre requête pour appliquer le comportement SQL standard GROUP BY





mysql