Single-Value Rule
Fondamental : Principe de la "Single-Value Rule" établie par le standard SQL
Toute colonne de la clause GROUP BY doit désigner une colonne présente dans la clause SELECT :
soit comme attribut d'agrégation,
soit comme attribut présent dans une fonction d'agrégation.
Attention : Requête illégale
SELECT countrycode, citycode, COUNT(citycode)
FROM city
GROUP BY countrycode;
ERROR: column "city.citycode" must appear in the GROUP BY clause or be used in an aggregate function;
La requête est non standard et non logique car on cherche à mettre plusieurs données dans la case citycode après le GROUP BY (il y a plusieurs citycode par countrycode).
Elle sera refusée par tous les SGBD.
Complément : Single-Value Rule
Tolérance (de certains SGBD)
Requête non standard tolérée par certains SGBD
SELECT citycode, countrycode, AVG(population)
FROM city
GROUP BY citycode;
citycode | countrycode | avg
----------+-------------+------------------------
LLL | FR | 0.20000000000000000000
BAR | ES | 1.90000000000000000000
PAR | FR | 2.2000000000000000
LYO | FR | 0.50000000000000000000
ZAR | ES | 0.70000000000000000000
AMN | FR | 0.10000000000000000000
MAD | ES | 3.3000000000000000
La requête est non standard, même si c'est logiquement acceptable, car il n'y a qu'un countrycode par citycode ici, city étant une clé.
Certains SGBD comme Postgres accepte donc cette syntaxe, en ajoutant implicitement l'attribut qui manque au GROUP BY, car il n'y a pas d’ambiguïté si l'on analyse le graphe des DF[1] : citycode → countrycode. Mais le standard impose d'être explicite, car le SGBD a le droit de ne pas le deviner.
Tolérance partielle
Requête légale
SELECT ci.countrycode, co.name, count(*)
FROM city ci JOIN country co
ON ci.countrycode=co.countrycode
GROUP BY ci.countrycode, co.name;
countrycode | name | count
-------------+--------+-------
FR | France | 4
ES | Spain | 3
Requête non standard tolérée par certains SGBD
SELECT co.countrycode, co.name, count(*)
FROM city ci JOIN country co
ON ci.countrycode=co.countrycode
GROUP BY co.countrycode;
La requête est non standard, car co.name est dans le SELECT mais pas dans le GROUP BY. Comme dans l'exemple précédent certains SGBD accepteront cette requête grâce à la DF évidente : co.countrycode → co.name
Attention : Requête non standard non tolérée
Mais si l'on utilise à présent ci.countrycode à la place de co.countrycode...
SELECT ci.countrycode, co.name, count(*)
FROM city ci JOIN country co
ON ci.countrycode=co.countrycode
GROUP BY ci.countrycode;
ERROR: column "co.name" must appear in the GROUP BY clause or be used in an aggregate function
La requête est non standard, co.name doit être mentionné dans la clause GROUP BY. Logiquement on pourrait juger cela superflu, car par transitivité ci.countrycode → co.name, mais le SGBD (ici Postgres) ne va pas jusque là.
Conseil :
Il est donc conseillé d'appliquer le Single-Value Rule et de toujours expliciter tous les attributs dans le GROUP BY, pour éviter la dépendance au SGBD ou bien les erreurs liées à des variations mineures de syntaxe.