Fonctions d’agrégation SQL et GROUP BY

Apprends à répondre à des questions de synthèse à partir d’une table de base de données : combien, quel total, quelle moyenne, quelle valeur minimale et quelle valeur maximale. Utilise COUNT, SUM, AVG, MIN et MAX, regroupe les lignes avec GROUP BY pour obtenir un résultat par catégorie et conserve uniquement les groupes dont tu as besoin avec HAVING. Tu apprendras aussi comment les valeurs manquantes et la division entière modifient les résultats, comment arrondir les moyennes et les pourcentages, et comment vérifier les chiffres d’une requête de synthèse. Les exemples utilisent du SQL standard exécutable sur SQLite et PostgreSQL. Les différences avec MySQL, SQL Server et Oracle sont signalées lorsqu’elles comptent.

DébutantUnité 4 sur 6 de la formation Formation : SQL : requêtes SELECT, jointures et agrégation

Ce que tu vas apprendre

  1. Utiliser COUNT, SUM, AVG, MIN et MAX pour obtenir des valeurs de synthèse à partir de nombreuses lignes, choisir le type de comptage adapté et prévoir comment les valeurs manquantes modifient un résultat.
    • Calculer des totaux, des moyennes, des minimums et des maximums
      Utiliser SUM, AVG, MIN et MAX sur une table entière ou sur les lignes conservées par une clause WHERE, et combiner plusieurs de ces fonctions dans une même requête.
    • Compter les lignes, les valeurs et les valeurs distinctes
      Choisir entre COUNT(*), COUNT(column) et COUNT(DISTINCT column), et savoir comment chacun traite les valeurs répétées et manquantes.
    • Prévoir l’effet des valeurs NULL sur les agrégats
      Savoir que les agrégats ignorent les valeurs NULL, prévoir les résultats pour des entrées vides et remplacer NULL par une valeur par défaut lorsque la question le demande.
  2. Utiliser GROUP BY pour obtenir une ligne de synthèse par catégorie, par combinaison de valeurs ou par valeur calculée, et respecter la règle sur ce qu’une requête groupée peut afficher.
    • Synthétiser chaque catégorie avec GROUP BY
      Répartir une table en groupes qui partagent une valeur, calculer des agrégats par groupe, puis trier et limiter le résultat groupé.
    • Respecter la règle sur ce qu’une requête groupée peut afficher
      Savoir quelles colonnes peuvent figurer dans la liste SELECT d’une requête groupée, corriger l’erreur produite lorsque la règle n’est pas respectée et reconnaître les différences entre bases de données.
    • Regrouper selon plusieurs colonnes et selon des valeurs calculées
      Regrouper les lignes selon des combinaisons de colonnes et des expressions comme le mois d’une date ou une catégorie CASE, et lire le résultat plus détaillé.
  3. Conserver uniquement les groupes dont les totaux, les effectifs ou les moyennes remplissent une condition, et décider si une condition relève de WHERE ou de HAVING.
    • Conserver les groupes qui remplissent une condition
      Écrire des conditions HAVING sur des valeurs agrégées, y compris des agrégats qui ne sont pas affichés, pour filtrer un résultat groupé.
    • Choisir entre WHERE et HAVING
      Utiliser l’ordre logique d’une requête pour déterminer si une condition filtre des lignes ou des groupes, et prévoir comment ce choix modifie le résultat.
  4. Éviter la division entière, connaître le type de nombre renvoyé par chaque agrégat et arrondir les moyennes, les totaux et les pourcentages au bon moment.
    • Éviter la division entière dans les moyennes et les pourcentages
      Reconnaître quand la division d’agrégats fait perdre les décimales, corriger le problème avec un opérande décimal et connaître les différences de types de résultat entre bases de données.
    • Arrondir des résultats agrégés
      Arrondir les moyennes, les totaux et les pourcentages avec ROUND, arrondir au bon moment et gérer les différences entre SQLite et PostgreSQL.
  5. Combiner CASE avec des agrégats pour obtenir des comptages, des sommes et des pourcentages conditionnels, et traduire une question en une requête groupée dont tu peux vérifier les chiffres.
    • Compter et additionner selon une condition avec CASE
      Placer une expression CASE dans un agrégat pour calculer plusieurs comptages, sommes et pourcentages conditionnels dans une même requête groupée.
    • Construire et vérifier une requête de synthèse à partir d’une question
      Traduire une question métier en une requête groupée étape par étape, éviter de mélanger les niveaux de détail et vérifier l’exactitude des chiffres.

Fonctions d’agrégation SQL : cours

5 chapitres

1

Synthétiser des données avec les fonctions d’agrégation

Une table enregistre des événements individuels ; un rapport a souvent besoin de quelques nombres qui les décrivent ensemble. Les fonctions d’agrégation transforment les lignes en effectifs, totaux, moyennes et valeurs extrêmes. Choisir la fonction n’est qu’une partie du travail : tu dois aussi déterminer quelles lignes entrent dans le calcul et ce que signifient les valeurs manquantes. Nous utiliserons une petite table de commandes pour vérifier chaque réponse à la main avant de nous fier à la requête.

1.1 Calculer des totaux, des moyennes, des minimums et des maximums

Une fonction d’agrégation combine les valeurs de plusieurs lignes en un seul résultat. Oracle l’appelle aussi fonction de groupe. Sans GROUP BY, une requête d’agrégation traite toutes les lignes qui satisfont WHERE comme un seul groupe et renvoie une ligne de synthèse.

Partir de données vérifiables

Chaque ligne de orders représente une commande. Les colonnes de nombres ci-dessous contiennent des entiers ; order_id est la clé primaire. Les dates sont au format texte ISO dans SQLite et de type DATE dans PostgreSQL.

order_idcustomerregionamountquantitydiscountorder_date
1AnaEast1202102026-01-05
2BenWest801NULL2026-01-17
3AnaEast45352026-02-02
4ChenNorth2004NULL2026-02-14
5BenWest60102026-02-20
6DaraEast952NULL2026-03-03
7ChenNorth1505152026-03-09
8EliNULL301NULL2026-03-21
Choisir la mesure

SUM(amount) additionne les montants. AVG(amount) donne leur moyenne arithmétique. MIN(amount) trouve le plus petit montant et MAX(amount) le plus grand. Tu peux demander les quatre dans une seule requête :

SELECT SUM(amount) AS total, AVG(amount) AS avg_amount, MIN(amount) AS smallest, MAX(amount) AS largest FROM orders;

Le résultat est une ligne : total 780, moyenne 97,5, minimum 30 et maximum 200. Additionne les huit montants pour obtenir 780, puis divise par huit pour obtenir 97,5. Chaque fonction utilise les mêmes huit lignes en entrée. Des alias clairs après AS rendent les en-têtes du résultat utiles ; un en-tête généré comme sum indique peu de chose sur ce qui a été additionné.

Filtrer avant de calculer

Pour synthétiser les commandes de East, écris SELECT COUNT(*) AS orders, SUM(amount) AS total FROM orders WHERE region = 'East';. Le filtre conserve les montants 120, 45 et 95. La requête renvoie trois commandes et un total de 260. WHERE choisit les lignes en entrée avant l’exécution de tout agrégat.

Un agrégat peut aussi prendre une expression calculée. Dans une table contenant quantity et unit_price, SUM(quantity * unit_price) calcule d’abord le chiffre d’affaires de chaque ligne, puis additionne ces chiffres d’affaires. Deux lignes, l’une de deux articles à 5 et l’autre de trois articles à 10, contribuent pour 10 et 30, soit un total de 40. SUM(quantity) * SUM(unit_price) multiplie quant à lui 5 par 15 et donne 75. Placer le calcul dans SUM conserve le prix correspondant à chaque quantité.

Interpréter correctement les valeurs extrêmes

MIN(order_date) vaut 2026-01-05 et MAX(order_date) vaut 2026-03-21. Les valeurs de date et les dates au format texte ISO se trient chronologiquement. Un texte tel que '03/21/2026' suit l’ordre des caractères, qui ne correspond pas toujours à l’ordre des dates. Les valeurs textuelles extrêmes suivent aussi la collation de la base de données, c’est-à-dire ses règles de comparaison du texte. Ici, les clients aux extrémités sont 'Ana' et 'Eli' ; un mélange de majuscules et de minuscules peut modifier l’ordre du texte.

MAX(amount) renvoie un montant, et non la commande entière qui le contient. Pour afficher un client ayant passé une commande du montant le plus élevé, utilise SELECT customer, amount FROM orders ORDER BY amount DESC LIMIT 1;. PostgreSQL rejette une colonne simple customer à côté de MAX(amount) sans regroupement approprié. SQLite possède une règle particulière pour un seul MIN ou MAX qui peut renvoyer une colonne voisine de la ligne contenant la valeur extrême, mais les valeurs extrêmes ex aequo nécessitent toujours une règle de départage.

Points clés

  • Un agrégat renvoie une valeur pour un ensemble de lignes.
  • WHERE sélectionne les lignes utilisées par l’agrégat.
  • Calcule la contribution de chaque ligne dans SUM lorsque les valeurs doivent rester associées.
  • MIN et MAX suivent l’ordre des nombres, des dates ou du texte.
  • Une valeur extrême ne permet pas d’identifier une ligne entière.

1.2 Compter les lignes, les valeurs et les valeurs distinctes

« Combien ? » peut porter sur les lignes, les valeurs enregistrées ou les valeurs différentes. Ce sont des comptages différents, même lorsqu’ils donnent par hasard le même nombre dans une petite table.

Trois formes de COUNT
ExpressionCe qu’elle compte
COUNT(*)Toutes les lignes en entrée
COUNT(region)Les lignes dont la région n’est pas NULL
COUNT(DISTINCT region)Les différentes valeurs de région non NULL

Dans la table des commandes, les régions sont East, West, East, North, West, East, North et NULL. SELECT COUNT(*) AS order_rows, COUNT(region) AS with_region, COUNT(DISTINCT region) AS regions FROM orders; renvoie 8, 7 et 3. Les noms de région répétés sont comptés séparément par COUNT(region), mais chaque nom ne contribue qu’une fois au comptage des valeurs distinctes.

Pour répondre à « Combien de clients différents ont commandé ? », utilise COUNT(DISTINCT customer). Ana, Ben et Chen apparaissent chacun deux fois, tandis que Dara et Eli apparaissent une fois : la réponse est donc cinq clients. COUNT(customer) renvoie huit, car chaque commande indique un client. Ce comptage mesure les lignes de commande qui nomment un client, et non les personnes.

Un zéro enregistré compte aussi

Les remises sont 10, NULL, 5, NULL, 0, NULL, 15 et NULL. COUNT(discount) renvoie quatre. Le zéro indique une valeur connue et compte comme 10, 5 et 15. Une chaîne vide est aussi une valeur dans SQLite et PostgreSQL ; Oracle traite une chaîne vide comme NULL.

Soustrais le nombre de valeurs non NULL du nombre de lignes pour mesurer les données manquantes : SELECT COUNT(*) - COUNT(region) AS missing_region FROM orders; renvoie un. Cela fonctionne parce que les deux comptages utilisent exactement les mêmes lignes en entrée.

Listes distinctes et comptages distincts

SELECT DISTINCT region FROM orders; liste East, West, North et une ligne NULL. Son rôle est de renvoyer les différentes valeurs, et NULL reste dans cette liste. COUNT(DISTINCT region) renvoie trois, car le comptage ignore NULL. Ne déduis pas un nombre de valeurs distinctes en comptant une liste sans avoir décidé si sa ligne NULL doit être incluse.

DISTINCT peut aussi figurer dans SUM ou AVG. Les quantités sont 2, 1, 3, 4, 1, 2, 5 et 1. Leur somme ordinaire est de 19. SUM(DISTINCT quantity) ne conserve que 1, 2, 3, 4 et 5, ce qui donne 15. Les quantités répétées correspondent généralement à de véritables ventes supplémentaires. Les supprimer change la mesure ; cela ne corrige pas des enregistrements en double.

Compter les combinaisons en deux étapes

Pour obtenir les paires région-client différentes, crée d’abord une liste distincte :

SELECT COUNT(*) FROM (SELECT DISTINCT region, customer FROM orders) AS pairs;

La requête interne renvoie cinq paires : East/Ana, East/Dara, North/Chen, West/Ben et NULL/Eli. Le COUNT(*) externe compte ces cinq lignes, y compris NULL/Eli. Cette forme fonctionne dans SQLite et PostgreSQL. MySQL accepte aussi COUNT(DISTINCT region, customer), mais cette forme exclut les combinaisons contenant NULL et peut donc répondre à une autre question. Dans SQLite et PostgreSQL, la forme avec des éléments séparés par une virgule est invalide.

Enfin, un comptage ne renvoie jamais NULL. SELECT COUNT(*) FROM orders WHERE region = 'South'; renvoie une ligne de synthèse contenant zéro, car aucune commande ne correspond.

Points clés

  • Choisis entre les lignes, les valeurs enregistrées et les valeurs enregistrées différentes.
  • Zéro est une valeur enregistrée : COUNT(column) l’inclut donc.
  • Une liste distincte peut inclure NULL ; COUNT(DISTINCT column) l’ignore.
  • SUM(DISTINCT x) supprime les valeurs répétées, y compris les répétitions légitimes.
  • Compte les combinaisons distinctes en comptant les lignes d’un résultat interne distinct.
  • COUNT renvoie zéro pour une entrée vide.

1.3 Prévoir l’effet des valeurs NULL sur les agrégats

NULL signifie qu’une valeur est manquante ou inconnue. Il modifie les valeurs reçues par un agrégat : un total ou une moyenne peut donc être valide en SQL tout en mesurant autre chose que ce que tu voulais.

Déterminer le dénominateur

Supposons que scores contienne Ana 80, Ben NULL, Chen 70 et Dara 90. SUM(score) vaut 240, COUNT(score) vaut trois et COUNT(*) vaut quatre. AVG(score) vaut 80 : les trois scores enregistrés totalisent 240 et sont divisés par trois.

Les cinq agrégats standard ignorent les arguments NULL. COUNT(*) compte toutes les lignes parce qu’il n’évalue pas d’argument de colonne. MIN(score) vaut 70 et MAX(score) vaut 90 ; NULL ne devient ni le plus petit ni le plus grand score. C’est différent du tri, où les valeurs NULL occupent une extrémité du résultat : en premier dans un tri croissant sous SQLite, en dernier dans un tri croissant sous PostgreSQL.

Une moyenne calculée à la main nécessite le nombre de valeurs non NULL : 1.0 * SUM(score) / NULLIF(COUNT(score), 0). L’opérande décimal conserve les résultats fractionnaires et NULLIF transforme un diviseur nul en NULL. Une division par COUNT(*) donnerait 60 et traiterait en pratique le score manquant comme un zéro.

Déterminer le sens d’une valeur par défaut

COALESCE renvoie son premier argument non NULL. Si Ben n’a pas été noté, laisse le score manquant et calcule la moyenne des résultats connus. Si un examen manqué est enregistré comme NULL mais doit compter pour zéro, AVG(COALESCE(score, 0)) calcule la moyenne de 80, 0, 70 et 90, soit 60. Le sens des données détermine si ce remplacement est justifié.

Compare le placement de COALESCE à l’intérieur et à l’extérieur d’une fonction. AVG(COALESCE(score, 0)) modifie les valeurs utilisées pour la moyenne. COALESCE(AVG(score), 0) modifie uniquement un résultat final NULL ; pour ces scores, il donne toujours 80. NVL(x, 0) dans Oracle est une autre forme à deux arguments pour remplacer NULL.

Distinguer l’absence de lignes de l’absence de valeurs enregistrées

Avec WHERE region = 'South', aucune commande ne reste. Une requête d’agrégation sans GROUP BY renvoie tout de même une ligne : COUNT(*) vaut zéro, tandis que SUM(amount), AVG(amount), MIN(amount) et MAX(amount) valent NULL. Pour afficher un total vide sous la forme zéro, utilise COALESCE(SUM(amount), 0). SQLite propose aussi TOTAL(amount), qui renvoie 0.0 pour une entrée vide.

Conserve maintenant les quatre commandes dont la remise est NULL. Il y a des lignes, mais aucune valeur de remise enregistrée : COUNT(*) vaut quatre, COUNT(discount) vaut zéro et SUM(discount) vaut NULL. Zéro valeur enregistrée et quatre valeurs manquantes sont deux constats différents.

Vérifier les expressions avant leur entrée dans SUM

Un calcul arithmétique avec NULL produit NULL. Dans SUM(amount - discount), les quatre commandes sans remise enregistrée n’apportent aucune valeur. Seules les lignes dont la remise est connue contribuent : 110, 40, 60 et 135, soit un total de 345.

Si une remise manquante signifie qu’il n’y a pas de remise, écris SUM(amount - COALESCE(discount, 0)). Chaque commande contribue alors au résultat ; le montant total de 780 moins les remises enregistrées de 30 donne 750. Entourer la somme entière de COALESCE ne rétablirait pas les commandes omises, car 345 n’est déjà pas NULL.

Pour repérer les valeurs manquantes, utilise IS NULL ou IS NOT NULL. WHERE discount IS NULL trouve quatre commandes. discount = NULL n’est jamais vrai et ne peut donc pas les sélectionner.

Points clés

  • AVG(x) divise par le nombre de valeurs non NULL.
  • Un COALESCE intérieur modifie les entrées ; s’il est placé à l’extérieur, il modifie un résultat NULL.
  • Une entrée vide donne zéro pour COUNT et NULL pour les quatre autres agrégats.
  • NULL dans une expression arithmétique peut supprimer la contribution d’une ligne.
2

Regrouper des lignes et synthétiser chaque groupe

Un total sur toute la table répond à une question, mais de nombreux rapports demandent un résultat par client, par région ou par mois. Le regroupement fixe ce niveau de détail avant l’exécution des agrégats. Tu suivras la formation des groupes à partir des lignes, choisiras des colonnes capables de décrire un groupe entier et verras comment l’ajout d’une colonne de regroupement modifie le rapport. Le tri détermine ensuite la présentation des résultats ; le regroupement seul ne leur donne pas d’ordre.

2.1 Synthétiser chaque catégorie avec GROUP BY

GROUP BY rassemble les lignes qui partagent une valeur de regroupement. Chaque agrégat s’exécute séparément dans chaque groupe et le résultat contient une ligne pour chaque groupe existant après filtrage.

Déterminer ce que signifie une ligne de résultat

« Total des ventes par région » demande une ligne de résultat par région. Commence par écrire cette phrase, puis utilise region comme colonne de regroupement :

SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region;

Les trois montants de East, 120, 45 et 95, forment un groupe. Son effectif est de trois et son total de 260. North compte deux commandes pour un total de 350 ; West en compte deux pour un total de 140. La commande d’Eli forme un groupe de région NULL avec une commande d’un total de 30. Il y a quatre lignes de résultat, et non huit.

Lis la requête comme une succession d’étapes : FROM fournit les commandes, un éventuel WHERE retire des lignes, GROUP BY rassemble les lignes restantes par région et les agrégats synthétisent chaque ensemble. SELECT affiche son libellé et ses mesures. Le regroupement n’élimine pas les petites commandes d’un groupe ; elles contribuent toutes au résultat, sauf si un filtre sur les lignes les a retirées.

Garder les catégories manquantes visibles

Les lignes dont la colonne de regroupement vaut NULL appartiennent à un seul groupe NULL. C’est utile : un rapport peut montrer l’importance de l’activité sans région enregistrée. Il ne traite pas chaque région manquante comme une catégorie différente.

Pour afficher un libellé lisible, sélectionne COALESCE(region, 'No region') AS region_label et conserve GROUP BY region. Le libellé modifie la valeur affichée. Pour exclure ces lignes des calculs, ajoute WHERE region IS NOT NULL avant GROUP BY. Les totaux obtenus ont une somme de 750, car le montant de 30 d’Eli a été exclu.

Une requête groupée sur une entrée sans lignes ne renvoie aucun groupe. Par exemple, filtrer la table sur South puis regrouper par région ne renvoie aucune ligne de résultat. C’est différent d’un agrégat sur toute la table sans GROUP BY, qui produit une ligne de synthèse même lorsque l’entrée est vide.

Trier explicitement les groupes

GROUP BY ne garantit aucun ordre de sortie. Pour lister d’abord les régions aux totaux les plus élevés, ajoute ORDER BY total DESC. L’alias total est autorisé dans ORDER BY ; ORDER BY SUM(amount) DESC produit le même tri.

Un rapport par client peut sélectionner les trois premiers totaux :

SELECT customer, SUM(amount) AS total FROM orders GROUP BY customer ORDER BY total DESC, customer LIMIT 3;

Il renvoie Chen 350, Ana 165 et Ben 140. La seconde clé de tri, customer, donne un ordre reproductible aux totaux ex aequo. LIMIT 3 ne renvoie que trois lignes ; il ne conserve pas tous les ex aequo à la limite. SQL Server exprime cette limite avec SELECT TOP 3, tandis qu’Oracle prend en charge FETCH FIRST 3 ROWS ONLY.

Lors d’un tri croissant des libellés de catégorie, SQLite place normalement NULL en premier et PostgreSQL en dernier. Précise l’ordre voulu lorsque cette position compte.

Vérifier la colonne de regroupement

SELECT DISTINCT region FROM orders et SELECT region FROM orders GROUP BY region renvoient les mêmes libellés de région distincts, y compris NULL. Utilise le regroupement lorsque tu as aussi besoin d’une mesure pour chaque libellé.

Un regroupement selon order_id, qui est unique, donne huit groupes d’une ligne chacun. Chaque effectif vaut un et chaque total de montant est égal au montant initial. Pour un rapport régional, ce résultat indique que la colonne de regroupement est trop détaillée.

Points clés

  • Précise ce que représente une ligne de résultat avant de choisir GROUP BY.
  • Toutes les valeurs de regroupement NULL forment un seul groupe.
  • Utilise ORDER BY pour fixer l’ordre du résultat et une seconde clé pour départager les ex aequo.
  • Un regroupement par clé de ligne unique produit des groupes d’une ligne.

2.2 Respecter la règle sur ce qu’une requête groupée peut afficher

Un rapport groupé doit faire tenir plusieurs lignes en entrée dans une seule ligne de résultat. Chaque valeur affichée doit donc avoir un sens clair pour l’ensemble du groupe. C’est pourquoi SQL limite les colonnes que tu peux sélectionner.

Respecter la règle de regroupement portable

Un élément d’un SELECT groupé doit être une colonne de regroupement, une expression construite à partir de colonnes de regroupement, un agrégat ou une constante. Considère cette requête :

SELECT region, customer, COUNT(*) FROM orders GROUP BY region;

East contient Ana, Ana et Dara. Le groupe a une seule région et un seul effectif, mais deux noms de clients différents. La requête n’indique pas quel client afficher dans l’unique résultat pour East. PostgreSQL rejette la colonne customer non regroupée.

Le même problème se pose sans GROUP BY : SELECT customer, SUM(amount) FROM orders associe un total sur toute la table à un nom individuel. Le total n’a pas un seul client pour le désigner.

Corriger la requête selon la question

Il existe trois corrections utiles, chacune ayant un sens différent :

  • Pour obtenir une ligne par région, retire customer : SELECT region, COUNT(*) FROM orders GROUP BY region;.
  • Pour obtenir une ligne par région et par client, regroupe selon les deux : SELECT region, customer, COUNT(*) FROM orders GROUP BY region, customer;.
  • Pour obtenir le nombre de clients par région, agrège les noms : SELECT region, COUNT(DISTINCT customer) AS customers FROM orders GROUP BY region;.

La dernière requête indique deux clients dans East et un dans chacun des autres groupes de régions. Ajouter une colonne à GROUP BY peut modifier le niveau de détail du rapport : choisis donc la correction en fonction de la question, et pas seulement du message d’erreur.

Une colonne de regroupement peut être omise de SELECT. SELECT COUNT(*) FROM orders GROUP BY region; est valide et renvoie quatre effectifs : trois, deux, deux et un, sans ordre garanti. Ces nombres sont difficiles à utiliser sans leurs libellés de région.

Appliquer la règle au-delà de SELECT

Un ORDER BY customer groupé pose le même problème lorsqu’on regroupe uniquement par région : quel client doit déterminer la place de East ? Les conditions HAVING d’une requête groupée doivent aussi décrire un groupe entier. Utilise-y des colonnes de regroupement ou des expressions d’agrégation.

Reconnaître le comportement permissif d’une base de données

SQLite accepte une colonne nue, c’est-à-dire une colonne sélectionnée qui n’est ni regroupée ni agrégée. Il prend une valeur dans une ligne en entrée du groupe. Un résultat apparemment correct comme 'Ana' à côté de East ne signifie pas qu’Ana représente toutes les commandes de cette région.

Avec exactement un agrégat MIN ou MAX intégré, SQLite prend les valeurs des colonnes nues dans une ligne contenant la valeur extrême. Les ex aequo et la présence de plusieurs agrégats de valeurs extrêmes rendent incertaine la ligne choisie. Ce raccourci est propre à la base de données. Trier les lignes initiales est plus clair lorsque tu cherches une commande dont le montant est extrême.

Le mode ONLY_FULL_GROUP_BY activé par défaut dans MySQL rejette les valeurs non regroupées qui ne sont pas déterminées par le groupe. ANY_VALUE(customer) autorise explicitement une valeur arbitraire, mais ne trouve pas le client associé à un total choisi. SQL Server et Oracle rejettent aussi les colonnes ordinaires non regroupées.

PostgreSQL et MySQL reconnaissent une exception pour la clé primaire : regrouper selon la clé primaire d’une table identifie une seule ligne, ce qui détermine ses autres colonnes. SELECT order_id, customer, SUM(amount) FROM orders GROUP BY order_id fonctionne dans PostgreSQL. Énumérer chaque colonne simple affichée dans GROUP BY reste la méthode portable.

Points clés

  • Chaque valeur affichée doit décrire l’ensemble du groupe.
  • Retirer, regrouper ou agréger une colonne répond à des questions différentes.
  • La règle de regroupement s’applique aussi à HAVING et à ORDER BY dans une requête groupée.
  • Les colonnes nues acceptées par SQLite peuvent masquer un rapport incorrect.
  • Une clé primaire utilisée pour le regroupement détermine les autres colonnes de sa ligne.

2.3 Regrouper selon plusieurs colonnes et selon des valeurs calculées

Certains rapports nécessitent une combinaison de catégories ou une catégorie calculée à partir de chaque ligne. SQL peut regrouper selon plusieurs colonnes ou selon une expression. Le choix essentiel reste ce que représente une ligne de résultat.

Regrouper selon une combinaison

GROUP BY region, customer ne rassemble les lignes que lorsque les deux valeurs correspondent. Sur la table des commandes, exécute :

SELECT region, customer, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region, customer ORDER BY region, customer;

Les résultats sont East/Ana : deux commandes, 165 ; East/Dara : une, 95 ; North/Chen : deux, 350 ; West/Ben : deux, 140 ; et NULL/Eli : une, 30. La somme des deux résultats de East est égale au total régional de 260.

Un regroupement selon customer, region forme les mêmes combinaisons. L’ordre des colonnes dans GROUP BY ne trie pas le résultat. La clause ORDER BY distincte ci-dessus détermine son affichage, sous réserve de la position de NULL par défaut dans chaque base de données.

Seules les combinaisons présentes dans l’entrée apparaissent. Il n’y a pas de ligne West/Ana avec un effectif de zéro. Le regroupement synthétise les lignes existantes ; il ne crée pas toutes les paires possibles de libellés de catégories.

Ajouter des détails seulement si nécessaire

L’ajout d’une colonne ne divise un groupe que si ses lignes contiennent des valeurs différentes dans cette colonne. Ici, le regroupement par client seul donne déjà cinq groupes. L’ajout de la région en donne toujours cinq, car chaque client n’a qu’une seule valeur de région. Ajouter order_date à un rapport régional crée des groupes plus petits pour les différentes dates et change la question à laquelle le rapport répond.

Regrouper les dates par année et par mois

Dans SQLite, utilise strftime('%Y-%m', order_date) pour créer un libellé comme '2026-02' :

SELECT strftime('%Y-%m', order_date) AS month, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY strftime('%Y-%m', order_date) ORDER BY month;

Janvier compte deux commandes pour un total de 200, février en compte trois pour un total de 305 et mars en compte trois pour un total de 275. Dans PostgreSQL, remplace les deux occurrences de strftime('%Y-%m', order_date) par to_char(order_date, 'YYYY-MM') pour une colonne DATE.

Un regroupement selon le seul numéro du mois combine les mêmes mois de différentes années. Janvier 2025 et janvier 2026 formeraient un seul groupe. Conserver l’année dans l’expression de regroupement permet de distinguer les mois du calendrier.

Répéter l’expression dans GROUP BY rend le regroupement explicite. SQLite, PostgreSQL et MySQL acceptent aussi l’alias de sortie, comme dans GROUP BY month ; SQL Server n’accepte pas à cet endroit un alias SELECT du même niveau.

Créer des catégories avec CASE

Une expression CASE peut attribuer un libellé à chaque commande avant le regroupement :

SELECT CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END AS size, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END;

La catégorie large contient 120, 200 et 150 : trois commandes pour un total de 470. La catégorie small contient cinq commandes pour un total de 310. Le seuil est inclus : un montant d’exactement 100 appartient donc à 'large'. La même expression CASE figure dans l’affichage et dans le regroupement afin que les deux utilisent la même définition des catégories.

Points clés

  • Plusieurs colonnes de regroupement identifient les combinaisons présentes dans les données.
  • L’ajout d’une colonne ne divise que les groupes dans lesquels cette colonne varie.
  • Inclus l’année en plus du mois pour distinguer les mois du calendrier.
  • Utilise la même expression de catégorie pour le libellé sélectionné et pour le regroupement.
  • GROUP BY ne crée pas les combinaisons absentes avec des effectifs nuls.
  • L’ordre des colonnes de regroupement ne détermine pas l’ordre du résultat.
3

Filtrer des résultats groupés avec HAVING

Un filtre peut modifier les lignes utilisées dans un calcul ou déterminer quelles synthèses terminées apparaissent dans un rapport. Ces choix répondent à des questions différentes. Tu utiliseras HAVING pour conserver des groupes selon leur effectif, leur total ou leur moyenne, puis tu le combineras avec WHERE sans modifier le sens recherché. Suivre l’ordre logique d’une requête permet de placer plus facilement chaque condition et de prévoir le résultat avant d’exécuter le code SQL.

3.1 Conserver les groupes qui remplissent une condition

HAVING teste les groupes après le calcul de leurs agrégats. Utilise-le pour une demande comme « régions dont le total des ventes dépasse 200 ». La condition décrit chaque total régional, et non une commande individuelle.

Calculer d’abord, conserver les groupes ensuite

SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region HAVING SUM(amount) > 200;

Avant HAVING, les totaux régionaux sont East 260, North 350, West 140 et NULL 30. La condition conserve East avec trois commandes et North avec deux. Elle retire les deux autres groupes du résultat ; elle ne retire pas certaines commandes à l’intérieur de East ou de North.

Dans une requête SQL écrite, place HAVING après GROUP BY et avant ORDER BY. Le tri s’applique ensuite aux groupes conservés par la condition.

Filtrer selon des mesures non affichées

SELECT region FROM orders GROUP BY region HAVING COUNT(*) >= 2; renvoie East, North et West. La base de données peut compter les lignes d’un groupe pour décider s’il remplit la condition sans afficher ce nombre. HAVING et SELECT n’ont pas besoin de listes d’agrégats identiques.

Tu peux combiner des conditions sur les groupes. HAVING COUNT(*) >= 2 AND AVG(amount) > 80 conserve East et North. East compte trois commandes et une moyenne d’environ 86,67 ; North en compte deux et une moyenne de 175. West compte assez de commandes, mais sa moyenne n’est que de 70. Les deux tests doivent être satisfaits, car ils sont reliés par AND ; avec OR, un seul test suffirait.

Trouver les valeurs répétées

Le regroupement et le comptage permettent aussi de trouver des doublons :

SELECT customer, COUNT(*) AS orders FROM orders GROUP BY customer HAVING COUNT(*) > 1;

Ana, Ben et Chen ont chacun deux commandes et remplissent la condition. Dara et Eli en ont une et ne la remplissent pas. Pour trouver les adresses électroniques répétées dans une table de clients, le même modèle regroupe selon email et conserve les effectifs supérieurs à un. L’effectif est le nombre d’enregistrements qui partagent cette valeur.

Utiliser l’expression nécessaire à la condition

Répète l’agrégat dans HAVING : HAVING SUM(amount) > 200. PostgreSQL et le SQL standard n’autorisent pas l’alias de sortie total dans cette condition au même niveau, contrairement à SQLite et MySQL. Un alias peut être utilisé sans problème dans un ORDER BY total DESC ultérieur.

Une valeur arrondie affichée et la valeur testée peuvent différer. La moyenne exacte de East est de 260 divisé par trois. Si tu sélectionnes ROUND(AVG(amount), 2) mais écris HAVING AVG(amount) > 86.67, East est retiré : sa moyenne non arrondie est inférieure à 86,67. North reste. La condition utilise exactement l’expression écrite dans HAVING. Seul HAVING ROUND(AVG(amount), 2) ... testerait la valeur arrondie.

Filtrer le groupe global unique

HAVING peut aussi fonctionner sans GROUP BY explicite. SELECT COUNT(*) FROM orders HAVING COUNT(*) > 5; traite les huit commandes comme un seul groupe, satisfait le test et renvoie une ligne contenant huit. Remplacer la condition par COUNT(*) > 10 ne renvoie aucune ligne, et non une ligne contenant zéro.

PostgreSQL prend en charge ce modèle, tout comme SQLite depuis la version 3.39.0. Dans une installation SQLite plus ancienne, une requête utilisant HAVING nécessite un GROUP BY explicite.

Points clés

  • HAVING conserve ou retire des groupes dont les agrégats ont été calculés.
  • Un agrégat de HAVING n’a pas besoin de figurer dans SELECT.
  • Combine les tests sur les groupes avec AND, OR et NOT.
  • Répète les expressions d’agrégation dans HAVING pour obtenir des requêtes portables.
  • Une condition teste sa propre expression, qui peut ne pas être arrondie.

3.2 Choisir entre WHERE et HAVING

Une condition doit être placée là où ce qu’elle décrit existe. Les commandes individuelles existent avant le regroupement. Un total régional n’existe qu’après le regroupement et l’addition des commandes.

Suivre l’ordre logique

Une requête SQL s’écrit dans l’ordre SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT. Pour raisonner sur le résultat, suis cet ordre logique :

  1. FROM fournit les lignes.
  2. WHERE conserve les lignes qui remplissent la condition.
  3. GROUP BY forme des groupes et les agrégats calculent leurs mesures.
  4. HAVING conserve les groupes qui remplissent la condition.
  5. SELECT produit les valeurs de sortie ; DISTINCT supprime les lignes de résultat en double si cela est demandé.
  6. ORDER BY trie le résultat et LIMIT conserve le nombre de lignes demandé.

La base de données peut organiser son exécution interne autrement.

Placer chaque condition au bon niveau
DemandeClause
Commandes avec amount >= 60WHERE
Commandes dans une plage de dates donnéeWHERE
Régions avec SUM(amount) > 200HAVING
Clients ayant passé plus d’une commandeHAVING COUNT(*) > 1

WHERE SUM(amount) > 200 échoue parce que le total n’existe pas encore à l’étape du filtrage des lignes. Une condition sur les lignes comme region = 'East' peut être évaluée avant le regroupement et appartient à WHERE.

Suivre les deux filtres

SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders WHERE amount >= 60 GROUP BY region HAVING SUM(amount) > 200;

Retire d’abord les commandes de 45 et de 30. East contient maintenant 120 et 95, North contient 200 et 150, et West contient 80 et 60. Calcule ensuite les totaux de 215, 350 et 140. Enfin, conserve les totaux supérieurs à 200. Le résultat est East avec deux commandes et 215, et North avec deux commandes et 350. La région NULL n’a plus de lignes et ne forme donc jamais de groupe.

Ne pas changer la question en déplaçant un filtre

« Pour chaque région, calculer la moyenne des seules commandes de 60 ou plus » utilise WHERE amount >= 60. La moyenne de East devient 107,5 à partir de 120 et 95.

HAVING MIN(amount) >= 60 demande les régions où chaque montant non NULL atteint le seuil. East est retiré parce que son minimum est de 45 ; North et West restent avec leurs commandes initiales. Le déplacement du test a changé le sens : au lieu de sélectionner des commandes individuelles, il accepte ou rejette des régions entières.

Pour ce rapport régional, region <> 'West' donne le même résultat dans WHERE ou dans HAVING : East et North restent, et le groupe NULL ne satisfait pas non plus la comparaison. WHERE énonce directement la restriction sur les lignes et l’applique avant le regroupement. Pour conserver aussi les régions manquantes, la condition doit comprendre explicitement OR region IS NULL.

Les alias SELECT ne sont pas disponibles dans les clauses WHERE et HAVING antérieures dans PostgreSQL. SQLite permet davantage d’utilisations des alias, mais écrire la colonne d’entrée ou l’expression en entier rend l’étape visée plus claire.

Points clés

  • WHERE modifie les entrées des agrégats ; HAVING filtre les résultats agrégés.
  • Place les conditions portant sur l’effectif, le total ou la moyenne d’un groupe dans HAVING.
  • Pour prévoir un résultat, suis le filtrage des lignes avant le regroupement.
  • Un test sur le minimum d’un groupe peut retirer le groupe entier.
4

Calculer des résultats exacts et correctement arrondis

Une requête peut choisir les bonnes lignes et perdre malgré tout la partie fractionnaire de sa réponse. Les types de nombres déterminent la division et les résultats des agrégats, tandis que l’arrondi détermine le nombre de décimales affichées. Tu conserveras les décimales pendant les calculs, choisiras une façon adaptée de traiter un dénominateur vide et n’arrondiras que la mesure finale. Une même expression courte peut se comporter différemment selon la base de données : chaque différence pertinente est donc indiquée.

4.1 Éviter la division entière dans les moyennes et les pourcentages

La division de deux nombres entiers peut supprimer la partie fractionnaire avant même l’affichage de la réponse. Cela compte lorsque tu construis une moyenne ou un pourcentage à partir de totaux et d’effectifs.

Utiliser un opérande décimal avant la division

Dans SQLite et PostgreSQL, 7 / 2 renvoie 3. Avec des entrées entières, SUM(quantity) / COUNT(*) sur la table des commandes renvoie 2 : la division de 19 articles par huit commandes perd sa partie fractionnaire. Dans PostgreSQL, SUM d’une colonne INTEGER renvoie BIGINT, ce qui donne encore une division entière dans ce cas.

Écris 1.0 * SUM(quantity) / COUNT(*) pour obtenir 2,375 dans les deux moteurs. La multiplication par 1,0 crée un opérande décimal avant la division. SUM(quantity) / COUNT(*) * 1.0 donne 2.0 parce que la division a déjà supprimé la partie fractionnaire. Les opérations de même priorité sont évaluées de gauche à droite.

Pour cette table, AVG(quantity) donne directement 2,375 dans SQLite et PostgreSQL. La formule écrite à la main est utile lorsque tu as besoin d’un dénominateur différent ou d’un pourcentage.

Calculer un pourcentage

Trois des huit commandes ont un montant d’au moins 100. Le nombre de ces commandes divisé par le nombre de toutes les commandes mesure leur part. Multiplie par 100,0 :

SELECT 100.0 * COUNT(CASE WHEN amount >= 100 THEN 1 END) / COUNT(*) AS pct_large FROM orders;

Le résultat est de 37,5. Utiliser l’entier 100 à la place produit 37 dans SQLite et pour une division de comptages entiers dans PostgreSQL. Un arrondi ultérieur ne changerait que l’affichage de 37.

Une requête sur toute la table peut ne trouver aucune ligne correspondante. NULLIF(COUNT(*), 0) renvoie NULL lorsque le comptage vaut zéro : 100.0 * COUNT(discount) / NULLIF(COUNT(*), 0) renvoie donc NULL pour une entrée vide. Un dénominateur nul sans protection provoque une erreur dans PostgreSQL ; SQLite renvoie NULL. Une part NULL peut clairement représenter « aucune commande à mesurer ».

Vérifier la base de données et le type d’entrée
Base de donnéesComportement à surveiller
SQLiteLa division entière tronque le résultat ; AVG renvoie un nombre à virgule flottante.
PostgreSQLLa division entière tronque le résultat ; AVG d’une entrée entière ou NUMERIC renvoie NUMERIC.
SQL ServerLa division entière tronque le résultat ; AVG d’une entrée entière renvoie un entier.
MySQL et Oracle/ conserve la partie fractionnaire pour des opérandes entiers.

Dans SQL Server, utilise AVG(quantity * 1.0) ou convertis les entrées en DECIMAL avant de calculer la moyenne. Dans PostgreSQL, SUM d’une colonne BIGINT renvoie NUMERIC : sa division ne se comporte donc pas nécessairement comme celle de SUM d’une colonne INTEGER. MySQL renvoie DECIMAL pour les sommes d’entrées entières.

Une conversion explicite peut aussi créer l’opérande décimal nécessaire : utilise CAST(SUM(quantity) AS REAL) dans SQLite ou CAST(SUM(quantity) AS NUMERIC) dans PostgreSQL. La conversion en NUMERIC de SQLite peut conserver un entier : cette conversion seule ne garantit donc pas une division décimale.

Distinguer les décimaux exacts des approximations

Les types à virgule flottante stockent des approximations binaires. Dans PostgreSQL, NUMERIC et DECIMAL prennent en charge les valeurs décimales exactes ; les additions en virgule flottante peuvent afficher de petits écarts comme 0.30000000000000004. L’affinité NUMERIC de SQLite ne permet pas un stockage décimal exact. Pour obtenir des totaux monétaires exacts dans SQLite, stocke les centimes sous forme d’entiers, additionne-les et divise par 100,0 pour l’affichage.

Points clés

  • Crée un opérande décimal avant de diviser des totaux ou des effectifs entiers.
  • Une multiplication après une division entière ne peut pas restituer les chiffres perdus.
  • Utilise NULLIF pour gérer un dénominateur nul.
  • Les types de résultat des agrégats dépendent à la fois du moteur et du type d’entrée.
  • L’affinité NUMERIC de SQLite ne permet pas un stockage décimal exact.
  • SQL Server nécessite des entrées décimales pour obtenir une moyenne fractionnaire d’entiers.

4.2 Arrondir des résultats agrégés

L’arrondi détermine le nombre de chiffres affichés dans un résultat. Garde toutes les décimales pendant les calculs jusqu’à l’étape finale, afin que les choix d’affichage ne modifient pas la mesure calculée.

Arrondir le résultat d’un agrégat

ROUND(x, n) arrondit à n chiffres après la virgule. ROUND(x) arrondit à l’entier. Par exemple, ROUND(3.14159, 2) vaut 3,14.

SELECT region, ROUND(AVG(amount), 2) AS avg_amount FROM orders GROUP BY region; donne 86,67 pour East, 175 pour North, 70 pour West et 30 pour la région NULL. SQLite peut afficher 175.0 tandis que le résultat NUMERIC de PostgreSQL affiche 175.00. Ces résultats représentent le même nombre. Arrondir un nombre et mettre en forme un libellé textuel de largeur fixe sont deux opérations différentes.

Arrondir après l’addition ou le calcul de la moyenne

Pour trois frais de 0,44, additionne d’abord pour obtenir 1,32, puis arrondis à une décimale pour obtenir 1,3. ROUND(SUM(fee), 1) suit cette séquence. SUM(ROUND(fee, 1)) arrondit chaque frais à 0,4 puis les additionne, ce qui donne 1,2. Un arrondi précoce a modifié le total.

De même, ROUND(100 * 1 / 3, 1) donne 33.0 dans SQLite et PostgreSQL parce que la division entière a déjà produit 33. ROUND(100.0 * 1 / 3, 1) conserve la partie fractionnaire et donne 33.3. Choisis le type de calcul avant d’arrondir.

La somme des parts arrondies peut ne pas être égale à 100 %. Trois parts égales peuvent chacune s’afficher sous la forme 33,3 %, soit un total de 99,9 %. Les parts sous-jacentes couvrent toujours l’ensemble. Recalculer une part arbitraire pour imposer le total affiché modifie le sens du nombre affiché.

Utiliser un type d’entrée pris en charge

PostgreSQL prend en charge ROUND(value, n) à deux arguments pour NUMERIC. Si temp est de type DOUBLE PRECISION, écris ROUND(CAST(AVG(temp) AS NUMERIC), 2). La moyenne de 20,5, 21,25 et 19,0 est de 20,25, et la conversion permet d’utiliser l’arrondi à deux arguments. Avec une colonne entière amount, la moyenne dans PostgreSQL est déjà de type NUMERIC : aucune conversion n’est nécessaire.

Pour les valeurs exactes NUMERIC de PostgreSQL, les valeurs à mi-chemin sont arrondies en s’éloignant de zéro : 2,5 devient 3 et -2,5 devient -3. SQLite donne aussi 3.0 et -3.0 pour ces exemples. L’arrondi en virgule flottante de PostgreSQL dépend de la plateforme ; l’arrondi au nombre pair le plus proche est courant. L’approximation binaire peut aussi placer un décimal juste en dessous de la valeur à mi-chemin visée. Ne fais pas d’un cas particulier d’arrondi en virgule flottante une règle générale pour le calcul décimal exact.

Remarquer deux autres différences entre dialectes

PostgreSQL, MySQL, SQL Server et Oracle utilisent un nombre négatif de décimales pour arrondir à gauche de la virgule. ROUND(1234.5, -2) donne 1 200. SQLite traite un second argument négatif comme zéro et donne 1235.0. Pour arrondir aux centaines dans SQLite, utilise ROUND(x / 100.0) * 100.

La conversion en entier dépend aussi de la base de données : SQLite supprime la partie fractionnaire, donc 2,9 devient 2 ; PostgreSQL l’arrondit à 3. Utilise ROUND lorsque le but est d’arrondir. TRUNC(x, n) dans PostgreSQL supprime des chiffres : TRUNC(2.97, 1) vaut 2.9, tandis que son arrondi à une décimale donne 3.0.

Points clés

  • Arrondis le résultat d’un agrégat après avoir terminé son calcul.
  • L’arrondi ne peut pas corriger une division entière effectuée auparavant.
  • La somme de pourcentages arrondis peut être de 99,9 % ou de 100,1 %.
  • Convertis une moyenne à virgule flottante de PostgreSQL en NUMERIC pour utiliser ROUND à deux arguments.
  • L’arrondi avec un nombre négatif de décimales et la conversion en entier diffèrent selon la base de données.
5

Répondre à des questions métier avec des requêtes de synthèse

Les rapports métier nécessitent souvent plusieurs mesures sur une même population : toutes les commandes, les commandes importantes et la part de ces dernières. L’agrégation conditionnelle conserve ces mesures côte à côte. Tu construiras ensuite un rapport complet à partir de sa question, vérifieras les totaux et les catégories manquantes, et utiliseras une seconde étape d’agrégation lorsque la question porte sur les clients ou d’autres groupes plutôt que sur des commandes individuelles.

5.1 Compter et additionner selon une condition avec CASE

L’agrégation conditionnelle permet à différentes mesures d’utiliser différentes contributions tout en conservant le même ensemble global de lignes. Une expression CASE détermine la contribution de chaque ligne à un comptage ou à une somme.

Compter les lignes qui remplissent la condition

COUNT(CASE WHEN amount >= 100 THEN 1 END) compte les commandes d’au moins 100. L’expression renvoie 1 pour une correspondance et NULL pour les autres lignes, car elle n’a pas de ELSE. COUNT ignore ces NULL, ce qui laisse trois correspondances dans la table des commandes.

SUM(CASE WHEN amount >= 100 THEN 1 ELSE 0 END) compte les correspondances en additionnant des uns et des zéros. En présence de lignes en entrée, le résultat est le même. Ce n’est pas le cas de COUNT(CASE WHEN amount >= 100 THEN 1 ELSE 0 END) : 1 et 0 sont tous deux non NULL, donc cette expression compte les huit commandes.

Additionner les montants correspondants

Pour obtenir une somme conditionnelle, renvoie le montant lui-même :

SELECT region, COUNT(*) AS orders, COUNT(CASE WHEN amount >= 100 THEN 1 END) AS large_orders, SUM(CASE WHEN amount >= 100 THEN amount ELSE 0 END) AS large_total FROM orders GROUP BY region;

East compte trois commandes, dont une importante, pour un total de commandes importantes de 120. North compte deux commandes, toutes deux importantes, pour un total de 350. West compte deux commandes, aucune commande importante et un total de commandes importantes de zéro. Le groupe de région NULL compte une commande et affiche zéro pour les deux mesures relatives aux commandes importantes.

Le résultat conserve West parce que ses lignes d’entrée existent toujours. Ajouter WHERE amount >= 100 retirerait les lignes de West avant le regroupement, ce qui ferait disparaître West. Ce filtre ferait aussi compter uniquement les commandes importantes par COUNT(*), supprimant la comparaison avec l’ensemble des commandes.

Utiliser le bon dénominateur

Dans chaque région, calcule le pourcentage de commandes importantes avec ROUND(100.0 * COUNT(CASE WHEN amount >= 100 THEN 1 END) / COUNT(*), 1) AS pct_large. East donne 33,3, North 100,0, West 0,0 et le groupe NULL 0,0. Chaque dénominateur est le nombre de commandes du groupe concerné, et non celui des huit commandes de la table entière.

Pour un rapport sans regroupement qui peut ne contenir aucune ligne, protège le dénominateur avec NULLIF(COUNT(*), 0). Un comptage sur une entrée vide vaut zéro, mais un pourcentage sur une population vide n’a pas de dénominateur.

Créer plusieurs colonnes de catégories

Un seul résultat peut afficher un comptage par région :

SELECT COUNT(CASE WHEN region = 'East' THEN 1 END) AS east, COUNT(CASE WHEN region = 'West' THEN 1 END) AS west, COUNT(CASE WHEN region = 'North' THEN 1 END) AS north FROM orders;

Les effectifs sont trois, deux et deux. La commande d’Eli ne satisfait aucun de ces tests sur les régions nommées. Ajoute COUNT(CASE WHEN region IS NULL THEN 1 END) pour compter la commande dont la région est manquante. Comparer une région NULL à un nom ne produit pas une condition vraie.

Reconnaître d’autres syntaxes

PostgreSQL et SQLite depuis la version 3.30.0 prennent en charge COUNT(*) FILTER (WHERE amount >= 100). Le filtre s’applique à cet agrégat : un COUNT(*) voisin sans filtre compte donc toujours toutes les commandes. MySQL et SQL Server ne prennent pas en charge cette syntaxe d’agrégat avec FILTER ; la forme avec CASE fonctionne dans les deux.

SQLite et MySQL autorisent aussi SUM(amount >= 100) parce que les comparaisons produisent des valeurs de vérité numériques. PostgreSQL rejette SUM appliqué à des booléens. Utilise la forme avec CASE lorsqu’une requête doit fonctionner sur ces différents moteurs.

Points clés

  • Place des conditions dans les agrégats pour conserver ensemble des mesures portant sur différents sous-ensembles.
  • COUNT(CASE ... THEN 1 END) ignore les lignes qui ne remplissent pas la condition.
  • ELSE 0 fonctionne pour une somme conditionnelle, mais conduit un comptage conditionnel à compter aussi les lignes qui ne remplissent pas la condition.
  • Un pourcentage au sein d’un groupe utilise la population de ce groupe comme dénominateur.
  • Une clause FILTER d’agrégat ne modifie que les entrées de cet agrégat.
  • Utilise IS NULL pour compter séparément les catégories manquantes.

5.2 Construire et vérifier une requête de synthèse à partir d’une question

Une requête de synthèse part d’une question sur une population à un niveau de détail donné. Traduis ces choix avant d’écrire le code SQL, puis vérifie que le résultat répond toujours à la question initiale.

Construire le rapport dans l’ordre

Pose la question : « Pour chaque mois de 2026 comptant au moins trois commandes, combien de commandes ont été passées et quel était leur montant moyen, à deux décimales près ? »

  1. Les mesures sont COUNT(*) et AVG(amount).
  2. La granularité, c’est-à-dire le sens d’une ligne de résultat, est un mois du calendrier.
  3. La condition sur les lignes conserve les dates de 2026.
  4. La condition sur les groupes exige au moins trois commandes.
  5. Le résultat doit être trié par mois, avec la moyenne arrondie pour l’affichage.

Dans SQLite :

SELECT strftime('%Y-%m', order_date) AS month, COUNT(*) AS orders, ROUND(AVG(amount), 2) AS avg_amount FROM orders WHERE order_date >= '2026-01-01' AND order_date < '2027-01-01' GROUP BY strftime('%Y-%m', order_date) HAVING COUNT(*) >= 3 ORDER BY month;

Pour les valeurs de date PostgreSQL, remplace l’expression du mois aux deux endroits par to_char(order_date, 'YYYY-MM'). La plage de dates inclut le début de 2026 et exclut le début de 2027.

Janvier compte deux commandes et ne remplit pas la condition sur les groupes. Février compte trois commandes pour un total de 305, avec une moyenne de 101,67. Mars en compte trois pour un total de 275, avec une moyenne de 91,67. Les groupes conservés représentent six commandes, et non huit, car HAVING a retiré janvier.

Vérifier avant de filtrer les groupes

Exécute d’abord le rapport sans HAVING. La somme des effectifs de tous les groupes doit être égale au nombre de lignes obtenu avec le même filtre WHERE, et la somme des totaux doit être égale au total sans regroupement. Ici, ces vérifications donnent huit et 780. Ne compare pas les totaux des groupes conservés avec l’ensemble de l’entrée après l’exclusion de certains groupes.

Cherche un groupe NULL, examine l’ordre des résultats et recalcule un groupe en filtrant la table initiale. Pour East, WHERE region = 'East' doit donner trois commandes pour un total de 260. Un écart peut révéler une colonne de regroupement supplémentaire, un filtre sur les lignes mal placé ou une expression devenue NULL.

Distinguer la commande moyenne du client moyen

AVG(amount) vaut 97,5 par commande. La dépense moyenne par client porte sur une autre unité : les cinq totaux par client sont 165, 140, 350, 95 et 30. Leur moyenne est de 156.

Calcule-la en deux étapes :

SELECT AVG(total) AS avg_customer_total FROM (SELECT customer, SUM(amount) AS total FROM orders GROUP BY customer) AS per_customer;

La requête interne crée une ligne par client. La requête externe calcule la moyenne de ces lignes, chaque client contribuant une fois. Tous les clients étant nommés, 1.0 * SUM(amount) / COUNT(DISTINCT customer) donne le même résultat de 156. Si les nombres de commandes sont inégaux, la moyenne des montants des commandes correspond à un calcul différent.

Synthétiser les groupes eux-mêmes

Pour compter les clients ayant passé plus d’une commande, liste-les d’abord, puis compte leurs lignes :

SELECT COUNT(*) FROM (SELECT customer FROM orders GROUP BY customer HAVING COUNT(*) > 1) AS repeat_customers;

La réponse est trois. Imbriquer directement des agrégats, comme dans MAX(AVG(amount)) à un même niveau de requête, échoue dans SQLite et PostgreSQL. Pour trouver la région ayant la moyenne la plus élevée, trie les moyennes groupées : ORDER BY AVG(amount) DESC LIMIT 1 renvoie North avec 175. Oracle prend aussi en charge les fonctions de groupe imbriquées, mais un niveau de requête distinct rend les deux calculs explicites. Vérifie les ex aequo lorsqu’un rapport demande un premier résultat.

Points clés

  • Détermine les mesures, la granularité, les conditions sur les lignes et les conditions sur les groupes à partir de la question.
  • Vérifie les effectifs et les totaux des groupes avant de retirer des groupes avec HAVING.
  • Une moyenne par client utilise les totaux par client comme entrées.
  • Utilise une requête groupée interne et un agrégat externe pour synthétiser les groupes.

Fonctions d’agrégation SQL : exemples

5 Leçons Interactives

1

Transformer des lignes de commande en chiffres de synthèse fiables

13 étapes
Choisir des agrégats et des comptages, puis suivre les effets des valeurs manquantes.
  1. 1
    IntroductionLire la question du rapport

    Un responsable souhaite obtenir un total des commandes, un nombre de clients et une remise moyenne. Chacun semble être un simple nombre, mais chacun utilise les données d’entrée différemment. Chacun est un agrégat, qui transforme plusieurs lignes en une valeur, et un mauvais choix donne un chiffre trompeur. Nous construirons ces mesures à partir des huit commandes : nous combinerons d’abord les montants, puis choisirons ce qu’il faut compter et déterminerons enfin comment NULL modifie la moyenne. Demande-toi toujours ce qu’une ligne en entrée apporte au résultat.

  2. 2
    ExplicationCombiner les montants

    Un agrégat combine les valeurs de plusieurs lignes en une synthèse. SUM(amount) additionne les montants, AVG(amount) calcule leur moyenne, et MIN(amount) et MAX(amount) trouvent les valeurs extrêmes. Sans GROUP BY, toutes les commandes qui remplissent la condition forment un seul groupe. Tu peux sélectionner plusieurs agrégats ensemble, car chacun décrit ce même groupe de lignes en entrée.

  3. 3
    ExempleCalculer une synthèse complète

    Les montants des commandes sont 120, 80, 45, 200, 60, 95, 150 et 30. Leur total est de 780. La division de ce total par huit donne une moyenne de 97,5 ; le minimum est de 30 et le maximum de 200.

    SELECT SUM(amount) AS total, AVG(amount) AS mean_amount, MIN(amount) AS low, MAX(amount) AS high FROM orders;

    Le résultat est une ligne contenant quatre mesures nommées.

  4. 4
    ExempleChoisir les entrées avant l’addition

    Pose maintenant la question pour East uniquement. WHERE region = 'East' conserve les montants 120, 45 et 95 avant l’exécution de l’agrégat.

    SELECT SUM(amount) AS total FROM orders WHERE region = 'East';

    Le résultat est de 260. Les autres régions ne contribuent pas, car leurs commandes ne satisfont pas la condition sur les lignes. Un filtre sur les lignes en entrée modifie le total lui-même, et pas seulement son libellé affiché.

  5. 5
    DéfiAssocier une quantité à son prix

    Une table de ventes comporte deux lignes : une quantité de 4 au prix unitaire de 6, et une quantité de 2 au prix unitaire de 9. Que renvoie SUM(quantity * unit_price) et pourquoi la multiplication des deux sommes donne-t-elle un résultat différent ?

    ---reveal---

    Les chiffres d’affaires des lignes sont 24 et 18, donc la somme est de 42. La multiplication des sommes donne six fois 15, soit 90, car elle n’associe plus chaque quantité au prix de sa propre ligne.

  6. 6
    ExplicationCompter les enregistrements ou les clients

    Les commandes indiquent Ana, Ben, Ana, Chen, Ben, Dara, Chen et Eli. COUNT(customer) compte huit noms enregistrés, y compris les apparitions répétées. COUNT(DISTINCT customer) compte cinq noms différents.

    La formulation détermine le choix adapté : compter les commandes nécessite de compter les lignes, tandis que compter les clients nécessite de compter les clients distincts. Des noms identiques sur des commandes séparées sont des répétitions attendues, et non des clients supplémentaires.

  7. 7
    ExempleCompter la catégorie manquante

    La colonne des régions comporte huit lignes mais seulement sept valeurs enregistrées. COUNT(*) vaut huit, COUNT(region) vaut sept et COUNT(DISTINCT region) vaut trois.

    La soustraction du nombre de valeurs enregistrées au nombre de lignes donne une région manquante. Remarque qu’une liste distincte des régions comprendrait aussi une ligne NULL ; le comptage distinct ignore ce NULL au lieu de le traiter comme une quatrième région nommée.

  8. 8
    DéfiChoisir le bon comptage

    Une colonne de coupons contient NULL, 0, 8, 8 et 0. Quelles valeurs COUNT(*), COUNT(coupon) et COUNT(DISTINCT coupon) renvoient-ils, dans cet ordre ?

    ---reveal---

    Ils renvoient cinq, quatre et deux. Il y a cinq lignes, quatre valeurs enregistrées et deux valeurs enregistrées différentes, 0 et 8. Les zéros enregistrés comptent ; NULL n’entre dans aucun des deux comptages de colonne.

  9. 9
    ExplicationExclure un score inconnu

    Considère les scores 80, NULL, 70 et 90. Les scores enregistrés totalisent 240. AVG(score) divise par les trois scores enregistrés et renvoie 80.

    Il ne divise pas par les quatre lignes : un score manquant n’est pas un zéro connu. Si la valeur manquante représente un examen manqué qui doit être noté zéro, le calcul recherché devient AVG(COALESCE(score, 0)), ce qui donne 60.

  10. 10
    ExemplePlacer la valeur par défaut à la bonne étape

    La remise est manquante sur quatre commandes. Dans SUM(amount - discount), chacune des expressions de ces lignes devient NULL, donc seules les quatre autres contribuent. Leurs montants nets totalisent 345.

    Si une valeur manquante signifie qu’il n’y a pas de remise, utilise SUM(amount - COALESCE(discount, 0)). Les huit commandes contribuent alors et le total est de 750. Un COALESCE placé autour de la somme déjà calculée ne peut pas rétablir les contributions des lignes omises.

  11. 11
    DéfiTraiter un groupe sans valeurs connues

    Une requête conserve trois lignes dont les montants sont tous NULL. Que renvoient COUNT(*), COUNT(amount) et SUM(amount) ?

    ---reveal---

    Ils renvoient trois, zéro et NULL. Les lignes existent, mais aucun montant n’est enregistré pour être compté ou additionné. Une entrée vide donnerait aussi une somme NULL, mais son nombre de lignes serait de zéro. Utilise COALESCE(SUM(amount), 0) uniquement lorsque le rapport doit afficher ce total manquant sous la forme zéro.

  12. 12
    DéfiVérifier un calcul et sa population

    Quatre enregistrements de prestations comportent des frais de 20, 30, 40 et 50, avec des crédits de 2, NULL, 0 et NULL. Un crédit manquant signifie qu’il n’y a pas de crédit. Quel total net de frais et quel nombre de crédits enregistrés le rapport doit-il afficher ?

    ---reveal---

    Utilise SUM(charge - COALESCE(credit, 0)) pour obtenir un total net de 138, et COUNT(credit) pour obtenir deux crédits enregistrés. Le crédit nul compte comme enregistré ; remplacer NULL dans la somme conserve les quatre frais.

  13. 13
    RécapitulatifGarder la mesure liée à ses entrées

    Choisis l’agrégat en fonction de la question, puis suis les valeurs qui y entrent. Les comptages distinguent les lignes, les valeurs enregistrées et les valeurs différentes. Pour les moyennes et les calculs sur les lignes, vérifie ce que NULL exclut et si un remplacement a un sens réel. Lorsqu’une réponse paraît surprenante, examine les lignes conservées et leurs contributions avant de modifier le code SQL.

2

Construire un rapport au bon niveau de détail

14 étapes
Regrouper selon des catégories, corriger les colonnes ambiguës et créer des groupes combinés ou calculés.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionDéterminer ce que représente une ligne de résultat
  2. 2
    ExplicationRassembler les lignes par région
  3. 3
    ExempleGarder le groupe NULL visible
  4. 4
    ConseilTrier avant de conserver les premières lignes
  5. 5
    DéfiPrévoir le nombre de groupes restants
  6. 6
    ExplicationExpliquer pourquoi un nom est ambigu
  7. 7
    ExempleCorriger le rapport selon sa question
  8. 8
    ConseilReconnaître un résultat accepté par un système permissif
  9. 9
    DéfiChoisir une correction adaptée au sens
  10. 10
    ExempleDiviser un groupe selon une seconde valeur
  11. 11
    ExplicationCréer un libellé de mois du calendrier
  12. 12
    DéfiTrouver l’expression de regroupement
  13. 13
    DéfiVérifier la granularité et les libellés du rapport
  14. 14
    RécapitulatifLire chaque ligne comme un groupe
3

Placer les filtres avant ou après l’agrégation

10 étapes
Suivre WHERE et HAVING dans un rapport et prévoir comment leur placement modifie la réponse.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionDistinguer la population de la sélection
  2. 2
    ExplicationTester le groupe après calcul
  3. 3
    ExempleUtiliser un comptage sans l’afficher
  4. 4
    DéfiVérifier la valeur réellement comparée
  5. 5
    ExplicationSuivre les étapes logiques du résultat
  6. 6
    ExempleRetirer d’abord les petites commandes
  7. 7
    ExempleRetirer ensuite les petits totaux de groupes
  8. 8
    DéfiRepérer une question modifiée
  9. 9
    DéfiCombiner les restrictions sur les lignes et sur les groupes
  10. 10
    RécapitulatifDéterminer l’étape à partir de la condition
4

Conserver les parties fractionnaires et arrondir le résultat final

11 étapes
Suivre les types de nombres, éviter les dénominateurs nuls et arrondir les agrégats à la bonne étape.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionDistinguer le calcul de l’affichage
  2. 2
    ExempleTrouver où la partie fractionnaire disparaît
  3. 3
    ExplicationIntroduire le nombre décimal assez tôt
  4. 4
    ConseilProtéger un dénominateur vide
  5. 5
    DéfiCorriger une expression de pourcentage
  6. 6
    ExplicationArrondir la moyenne calculée
  7. 7
    ExempleVoir comment un arrondi précoce modifie un total
  8. 8
    DéfiVérifier une différence entre dialectes
  9. 9
    LienChoisir le type pour des montants exacts
  10. 10
    DéfiVérifier le type avant l’arrondi
  11. 11
    RécapitulatifSuivre le nombre à chaque étape
5

Construire et vérifier une synthèse métier

13 étapes
Créer des mesures sur des sous-ensembles, choisir la granularité d’un rapport et synthétiser des résultats groupés à deux niveaux de requête.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionConserver ensemble toutes les commandes et les commandes sélectionnées
  2. 2
    ExplicationFaire contribuer les lignes non correspondantes avec NULL
  3. 3
    ExempleGarder l’ensemble du groupe disponible
  4. 4
    ExempleAjouter le montant ou ajouter un
  5. 5
    DéfiConserver le dénominateur d’une part
  6. 6
    ExplicationTraduire la formulation métier
  7. 7
    ExempleConstruire le résultat mensuel
  8. 8
    ConseilVérifier avant de masquer les groupes
  9. 9
    ExplicationChanger l’unité d’entrée d’une moyenne
  10. 10
    ExempleLire les deux niveaux de requête
  11. 11
    DéfiChoisir la bonne unité pour la moyenne
  12. 12
    DéfiCompter uniquement les groupes de clients qui remplissent la condition
  13. 13
    RécapitulatifVérifier la population et la granularité

Fonctions d’agrégation SQL : QCM

40 Questions Pratiques en 4 séries

Série 1 : Lire des comptages, des groupes et des calculs10 Questions Pratiques

Question 1 sur 10

Une table de livraisons enregistre les distances 14, 22 et 35. Quelle valeur SUM(distance) renvoie-t-il ?
  1. 35
  2. 23.67
  3. 71
  4. 3
Afficher la réponseMasquer la réponse
Réponse : C
SUM additionne les trois distances, ce qui donne 71. La plus grande distance, 35, serait le résultat de MAX(distance), tandis qu’une moyenne diviserait la distance cumulée par trois ; aucun des deux ne répond à la demande d’un total.

Question 2 sur 10

Cinq demandes ont pour valeurs de statut closed, open, closed, open et open. Que renvoie COUNT(CASE WHEN status = 'closed' THEN 1 ELSE 0 END) ?
  1. 5
  2. 2
  3. 3
  4. 0
Afficher la réponseMasquer la réponse
Réponse : A
Chaque résultat de CASE est une valeur enregistrée : les demandes closed produisent 1 et les demandes open produisent 0. COUNT compte les deux, ce qui donne cinq. Pour ne compter que les deux demandes closed, omets ELSE afin que les lignes non correspondantes produisent NULL, ou additionne les indicateurs de un et de zéro avec SUM.

Question 3 sur 10

Quatre livraisons ont des délais de 6, NULL, 10 et 8 minutes. Un délai manquant signifie qu’il n’a pas été mesuré. Quelle moyenne AVG(delay) renvoie-t-il ?
  1. 6
  2. 24
  3. 10
  4. 8
Afficher la réponseMasquer la réponse
Réponse : D
Les trois délais mesurés totalisent 24 minutes et AVG divise par leur nombre, trois, ce qui donne huit minutes. Une division par les quatre lignes donnerait six minutes et remplacerait en pratique le délai inconnu par zéro, alors qu’aucune mesure de ce type n’a été enregistrée.

Question 4 sur 10

Une table de services contient les valeurs de département Sales, Support, Sales, NULL et NULL. Combien de lignes SELECT department, COUNT(*) FROM shifts GROUP BY department renvoie-t-il ?
  1. 5
  2. 3
  3. 2
  4. 4
Afficher la réponseMasquer la réponse
Réponse : B
La requête forme un groupe pour Sales, un pour Support et un pour la valeur de département manquante : elle renvoie donc trois lignes. Les valeurs de regroupement NULL sont rassemblées ; traiter chaque NULL comme un groupe distinct créerait une ligne de résultat supplémentaire que SQL ne produit pas.

Question 5 sur 10

Une table de pièces comporte plusieurs fournisseurs par catégorie. Le rapport nécessite une ligne par catégorie et le nombre de ses fournisseurs différents. Quelle liste SELECT convient à FROM parts GROUP BY category ?
  1. category, supplier, COUNT(*)
  2. category, COUNT(DISTINCT supplier)
  3. category, COUNT(supplier)
  4. category, MIN(supplier)
Afficher la réponseMasquer la réponse
Réponse : B
COUNT(DISTINCT supplier) transforme toutes les valeurs de fournisseur enregistrées dans une catégorie en un seul comptage des fournisseurs différents. Une valeur de fournisseur simple est ambiguë, car la catégorie peut en avoir plusieurs. COUNT(supplier) compterait les enregistrements comportant un fournisseur, y compris les apparitions répétées.

Question 6 sur 10

Une table de paiements PostgreSQL possède une colonne DATE paid_on avec des enregistrements de 2024 à 2026. Quelle expression de regroupement distingue chaque mois du calendrier ?
  1. EXTRACT(MONTH FROM paid_on)
  2. EXTRACT(YEAR FROM paid_on)
  3. paid_on
  4. to_char(paid_on, 'YYYY-MM')
Afficher la réponseMasquer la réponse
Réponse : D
L’expression année-mois donne à chaque mois du calendrier sa propre clé et distingue ainsi les mois de juin des différentes années. Le seul numéro du mois fusionnerait ces mois de juin, tandis qu’un regroupement selon la date complète diviserait un mois en groupes journaliers et modifierait le niveau de détail demandé.

Question 7 sur 10

Un rapport groupé contient les totaux par équipe Red 180, Blue 260 et Green 200. Quelles équipes restent après HAVING SUM(amount) > 200 ?
  1. Blue
  2. Blue et Green
  3. Red et Blue
  4. Green
Afficher la réponseMasquer la réponse
Réponse : A
Seule Blue a un total strictement supérieur à 200. Green est exactement au seuil et ne satisfait donc pas le test « supérieur à » ; elle satisferait >= 200. HAVING applique cette comparaison à chaque total d’équipe calculé : il conserve ou retire donc le résultat entier de chaque équipe.

Question 8 sur 10

Une requête PostgreSQL sélectionne la catégorie et le coût total, regroupe uniquement par catégorie et utilise ORDER BY supplier. Les catégories ont plusieurs fournisseurs. Comment afficher d’abord les catégories au coût le plus élevé sans changer la granularité ?
  1. Ajouter le fournisseur à GROUP BY.
  2. Utiliser ORDER BY supplier DESC.
  3. Utiliser ORDER BY SUM(cost) DESC.
  4. Ajouter le fournisseur à la liste SELECT.
Afficher la réponseMasquer la réponse
Réponse : C
Le tri selon SUM(cost) utilise une mesure définie pour chaque groupe de catégories et conserve une ligne par catégorie. Un fournisseur simple ne peut pas ordonner un groupe contenant plusieurs fournisseurs. Ajouter le fournisseur à GROUP BY rendrait la syntaxe valide, mais diviserait les catégories et modifierait le niveau de détail demandé pour le rapport.

Question 9 sur 10

Dans SQLite, des quantités entières totalisent 23 sur six lignes. Que renvoie SUM(quantity) / COUNT(*) * 1.0 ?
  1. 3.0
  2. 3.8333333333333335
  3. 4.0
  4. 23.0
Afficher la réponseMasquer la réponse
Réponse : A
La division entière a lieu d’abord : 23 divisé par six est tronqué à trois. Multiplier ce résultat par 1,0 donne 3.0 et ne peut pas restituer la partie fractionnaire perdue. Pour conserver la moyenne fractionnaire, introduis l’opérande décimal avant la division avec 1.0 * SUM(quantity) / COUNT(*).

Question 10 sur 10

Une table SQLite contient trois frais de 0,26. Une requête sélectionne ROUND(SUM(fee), 1) mais ne conserve le groupe global qu’avec HAVING SUM(fee) >= 0.8. Quel résultat renvoie-t-elle ?
  1. Une ligne contenant 0,8.
  2. Une ligne contenant 0,9.
  3. Une ligne contenant NULL.
  4. Aucune ligne.
Afficher la réponseMasquer la réponse
Réponse : D
Les frais totalisent 0,78, ce qui s’afficherait sous la forme 0,8 après arrondi. HAVING compare la somme non arrondie à 0,8 : le groupe ne remplit donc pas la condition et aucune ligne n’apparaît. Traiter la valeur arrondie affichée comme la valeur testée reviendrait à accepter un groupe dont le total réel est inférieur au seuil.
Série 2 : Choisir la population et le niveau de détail du rapport10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Une table de tickets contient les valeurs de priorité 0, NULL, 2, 2 et NULL. Que renvoie COUNT(priority) ?
  1. 5
  2. 3
  3. 2
  4. 1
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une table work_log comporte les colonnes consultant, year et hours. Un rapport doit donner un total d’heures par consultant pour 2025, en ne conservant que les totaux supérieurs à 120. Quelle forme de requête répond à cette demande ?
  1. WHERE year = 2025 AND hours > 120 GROUP BY consultant
  2. GROUP BY consultant, hours HAVING SUM(hours) > 120
  3. WHERE hours > 120 GROUP BY consultant, year
  4. WHERE year = 2025 GROUP BY consultant HAVING SUM(hours) > 120
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Une table stocke des dates de livraison sous forme de texte ISO : '2025-12-28', '2026-01-04' et '2025-02-19'. Que renvoient MIN(delivery_date) et MAX(delivery_date), dans cet ordre ?
  1. 2025-02-19 et 2026-01-04
  2. 2025-12-28 et 2026-01-04
  3. 2026-01-04 et 2025-02-19
  4. 2026-01-04 et 2025-12-28
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Une table SQLite contient les paires (ville, agent) (A, Jo), (A, Jo), (A, Kai), (NULL, Lee) et (NULL, Lee). Que renvoie SELECT COUNT(*) FROM (SELECT DISTINCT city, agent FROM visits) AS pairs ?
  1. 2
  2. 4
  3. 3
  4. 5
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Quatre réparations ont les valeurs (coût, avoir) suivantes : (50, 5), (80, NULL), (40, 0) et (30, NULL). NULL signifie qu’il n’y a pas d’avoir. Que valent SUM(cost - credit) et le coût net total recherché, dans cet ordre ?
  1. 195 et 195
  2. 85 et 85
  3. 115 et 195
  4. 85 et 195
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Les totaux par client sont Ali 90, Bea 120, Cam 120 et Dev 75. Quelles lignes ORDER BY total DESC, customer ASC LIMIT 2 conserve-t-il, en supposant que les noms sont triés par ordre alphabétique ?
  1. Ali 90 et Bea 120
  2. Bea 120 et Cam 120
  3. Cam 120 et Bea 120
  4. Bea 120 et Ali 90
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Une table de frais contient trois valeurs de 0,36. Que produisent ROUND(SUM(fee), 1) et SUM(ROUND(fee, 1)), dans cet ordre, si l’on ignore les infimes écarts d’affichage dus à la virgule flottante ?
  1. 1,2 et 1,1
  2. 1,1 et 1,1
  3. 1,1 et 1,2
  4. 1,2 et 1,2
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Une table contient les paires (site, salarié) (A, Ren), (A, Ren), (A, Sol), (B, Ren), (NULL, Sol) et (NULL, Sol). Combien de groupes obtient-on en regroupant par site, puis par site et par salarié ?
  1. 3 et 4
  2. 3 et 6
  3. 2 et 3
  4. 3 et 3
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Une liste d’inscriptions contient les valeurs de formation Safety, Safety, Tools, Tools, Tools et First Aid. Que renvoie SELECT training FROM roster GROUP BY training HAVING COUNT(*) >= 3 ?
  1. Safety et Tools
  2. Tools
  3. Tools et First Aid
  4. Aucune ligne
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

L’équipe A a les montants 20, 80 et 100 ; l’équipe B a 60 et 90. Que reste-t-il après WHERE amount >= 60 GROUP BY team HAVING AVG(amount) > 80 ?
  1. B avec une moyenne de 75.
  2. A avec une moyenne d’environ 66,67.
  3. A avec une moyenne de 90.
  4. A avec 90 et B avec 75.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 3 : Combiner valeurs manquantes, types et groupes10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Que renvoie SELECT 17 / 5 dans SQLite ?
  1. 3.4
  2. 4
  3. 0
  4. 3
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une requête regroupe des demandes par équipe, mais sélectionne un nom d’employé simple. Chaque équipe compte plusieurs employés. SQLite affiche un nom et PostgreSQL rejette la requête. Qu’est-ce qui explique cette différence ?
  1. SQLite regroupe automatiquement par employé ; PostgreSQL exige un groupe explicite.
  2. SQLite autorise une colonne nue ; le nom ne décrit pas toute l’équipe.
  3. SQLite renvoie le premier employé par ordre alphabétique ; PostgreSQL exige un tri explicite.
  4. SQLite retire les employés supplémentaires avant le regroupement ; PostgreSQL les conserve tous.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Le site L a les montants 30, 50 et 80 ; le site M a 20 et 40. Tu as besoin du pourcentage de commandes d’au moins 60 pour chaque site, y compris les sites qui n’en ont aucune. Quels pourcentages doivent apparaître ?
  1. L 100,0 % ; M absent.
  2. L 20,0 % ; M 0,0 %.
  3. L 33,3 % ; M 0,0 %.
  4. L 50,0 % ; M 0,0 %.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

La cliente Inez a les montants 20, 30 et 50 ; Omar a 200. Quels sont le montant moyen par commande et le montant total moyen par client, dans cet ordre ?
  1. 75 et 150
  2. 150 et 75
  3. 75 et 100
  4. 100 et 150
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une table de stock contient les lignes (département, quantité, prix) (A, 2, 7), (A, 3, 4) et (B, 5, 9). Que renvoie SELECT SUM(quantity * price) FROM stock WHERE department = 'A' ?
  1. 55
  2. 71
  3. 26
  4. 14
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Une colonne de région contient NULL, West, West, East et NULL. Que renvoie COUNT(DISTINCT region) ?
  1. 2
  2. 3
  3. 5
  4. 1
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Aucune ligne de jobs ne correspond à state = 'queued'. Que renvoie SELECT team, COALESCE(SUM(hours), 0) FROM jobs WHERE state = 'queued' GROUP BY team ?
  1. Une ligne d’équipe NULL avec zéro.
  2. Une ligne d’équipe NULL avec NULL.
  3. Une ligne de total nul pour chaque équipe.
  4. Aucune ligne.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Une table contient les valeurs de zone North, NULL, South, NULL et North. Après WHERE area IS NOT NULL GROUP BY area, quels sont les effectifs des groupes ?
  1. North 2 ; South 1 ; NULL 2.
  2. North 2 ; South 1.
  3. North 1 ; South 1.
  4. North 3 ; South 2.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Un rapport doit indiquer les montants moyens des factures par bureau, en ne retenant que les factures datées de 2025 et en n’affichant que les bureaux ayant plus de cinq factures correspondantes. Où placer le test sur la date et celui sur le nombre ?
  1. Les deux tests dans WHERE.
  2. Date dans HAVING ; nombre dans WHERE.
  3. Les deux tests dans HAVING.
  4. Date dans WHERE ; nombre dans HAVING.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Des commandes ont les valeurs (date, montant) (2025-01-10, 90), (2026-01-12, 140), (2026-01-20, 60) et (2026-02-03, 110). Regroupe-les par année-mois et selon CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END. Combien de groupes obtient-on ?
  1. 4
  2. 3
  3. 2
  4. 5
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 4 : Analyser et terminer des rapports complets10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Un rapport regroupe une table de réservations par salle. Quelle condition HAVING conserve les salles ayant au moins quatre réservations ?
  1. HAVING COUNT(*) >= 4
  2. HAVING COUNT(*) > 4
  3. HAVING COUNT(*) = 4
  4. HAVING COUNT(*) <= 4
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

L’agence A a les montants 10, 40 et 70 ; l’agence B a 30 et 50. Compare un regroupement après WHERE amount >= 30 avec un regroupement de toutes les lignes utilisant HAVING MIN(amount) >= 30. Quelles moyennes apparaissent ?
  1. WHERE : A 40 et B 40 ; HAVING : B 40 seulement.
  2. WHERE : A 55 et B 40 ; HAVING : A 55 et B 40.
  3. WHERE : A 55 et B 40 ; HAVING : B 40 seulement.
  4. WHERE : B 40 seulement ; HAVING : A 40 et B 40.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Un rapport sans regroupement peut ne contenir aucune ligne en entrée. Quelle expression donne le pourcentage de lignes ayant une valeur enregistrée, conserve les décimales et renvoie NULL pour une population vide dans SQLite comme dans PostgreSQL ?
  1. 100 * COUNT(value) / NULLIF(COUNT(*), 0)
  2. 100.0 * COUNT(value) / NULLIF(COUNT(*), 0)
  3. 100.0 * COUNT(value) / COALESCE(COUNT(*), 1)
  4. 100.0 * COUNT(*) / NULLIF(COUNT(value), 0)
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Dans PostgreSQL, temperature est de type DOUBLE PRECISION. Comment arrondir sa moyenne à deux décimales ?
  1. ROUND(AVG(temperature), 2)
  2. CAST(ROUND(AVG(temperature)) AS NUMERIC)
  3. ROUND(CAST(AVG(temperature) AS INTEGER), 2)
  4. ROUND(CAST(AVG(temperature) AS NUMERIC), 2)
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Dans PostgreSQL, COUNT(*) FILTER (WHERE paid = 1) figure à côté de COUNT(*) dans une requête groupée sans clause WHERE. Que restreint le filtre ?
  1. Tous les agrégats du groupe.
  2. Uniquement l’affichage du résultat final.
  3. Uniquement l’agrégat qui compte les paiements.
  4. Toutes les lignes avant la formation des groupes.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Le client U a les montants 40 et 70, V a 60, 60 et 10, et W a 150. Combien de clients ont au moins deux commandes et un total supérieur à 120 ?
  1. 2
  2. 3
  3. 5
  4. 1
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Une requête conserve quatre lignes dont les valeurs sont NULL, NULL, NULL et NULL. Que valent COUNT(*), COUNT(value) et MAX(value), dans cet ordre ?
  1. 4, 0, NULL
  2. 0, 0, NULL
  3. 4, 4, NULL
  4. 4, 0, 0
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Une table de visites contient les paires (client, zone) (Jo, East), (Jo, East), (Kai, West), (Kai, North), (Lee, NULL) et (Lee, NULL). Comment l’ajout de la zone au regroupement par client modifie-t-il le nombre de groupes ?
  1. Il reste à trois.
  2. Il passe de trois à quatre.
  3. Il passe de trois à six.
  4. Il passe de trois à cinq.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Un rapport groupé comprend les zones East, West et NULL. Un filtre sur les lignes est WHERE zone <> 'West'. Quels groupes de zones peuvent rester ?
  1. East et NULL.
  2. East et West.
  3. East seulement.
  4. NULL seulement.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Dans une table de commandes SQLite, mai 2025 contient les montants 20 et 100, mai 2026 contient 50 et 70, et juin 2026 contient 200. Un rapport doit afficher uniquement les mois de 2026 comptant au moins deux commandes, avec le montant moyen arrondi. Quel résultat répond à la demande ?
  1. 2026-05 : quatre commandes, moyenne de 60,00.
  2. 2026-05 : deux commandes, moyenne de 60,00.
  3. 2026-06 : une commande, moyenne de 200,00.
  4. 2026-05 : deux commandes, moyenne de 120,00.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Tu bloques sur ton propre exercice ? Aide aux Devoirs

Mots-Clés

58 Mots-Clés, chacun avec sa définition

A

Agrégation conditionnelle
L’agrégation conditionnelle fait dépendre la contribution de chaque ligne d’une condition, ce qui permet d’obtenir plusieurs mesures de sous-ensembles dans un seul rapport.
Un rapport régional peut afficher ensemble toutes les commandes et les commandes importantes sans filtrer d’abord les petites commandes.
Alias SELECT
Un alias SELECT est un nom de sortie attribué à une expression, qui peut être utilisé dans ORDER BY et dont les autres usages dépendent du dialecte.
PostgreSQL accepte ORDER BY total, mais exige que l’expression d’agrégation soit écrite en entier dans un HAVING du même niveau.
Arrondi final
L’arrondi final réduit la précision après le calcul complet de l’agrégat et évite l’accumulation des changements dus à l’arrondi préalable de chaque entrée.
Trois frais de 0,44 totalisent 1,32 avant d’être arrondis à 1,3 ; arrondir d’abord chaque frais produirait un total de 1,2.
AVG
AVG est une fonction d’agrégation qui calcule la moyenne arithmétique de ses entrées non NULL, en utilisant chaque valeur enregistrée une fois.
AVG(amount) donne 97,5 pour huit commandes dont les montants totalisent 780 ; il mesure le montant moyen d’une commande.

C

CAST
CAST convertit une valeur dans un type SQL demandé, avec des effets qui dépendent du type de destination et du moteur de base de données.
Dans SQLite, une conversion en REAL permet une division décimale, tandis qu’une conversion en NUMERIC peut laisser une valeur entière sous forme d’entier.
Catégorie CASE
Une catégorie CASE est un libellé attribué par des conditions dans une expression CASE, qui peut servir de base à un rapport groupé.
Un seuil amount >= 100 place une commande d’exactement 100 dans la catégorie nommée « large ».
Clause FILTER d’agrégat
Une clause FILTER d’agrégat restreint les entrées d’un agrégat tout en laissant les autres agrégats de la même requête libres d’utiliser d’autres lignes.
PostgreSQL peut placer un comptage filtré des commandes importantes à côté d’un comptage sans filtre de toutes les commandes du même groupe.
Clé année-mois
Une clé année-mois identifie un mois du calendrier avec son année et évite ainsi de fusionner le même mois de différentes années.
Les libellés « 2025-01 » et « 2026-01 » produisent des groupes distincts dans un rapport mensuel couvrant les deux années.
COALESCE
COALESCE est une fonction qui renvoie son premier argument non NULL et permet de choisir une valeur par défaut pour une entrée ou un résultat final.
COALESCE(SUM(amount), 0) affiche zéro lorsqu’une entrée vide produirait autrement un total NULL.
Collation
Une collation est un ensemble de règles que la base de données utilise pour comparer et ordonner du texte, notamment les règles sur l’effet de la casse.
Le minimum de valeurs textuelles peut changer selon la collation, même si les lignes et la requête MIN restent identiques.
Colonne de regroupement
Une colonne de regroupement fournit les valeurs qui déterminent les lignes en entrée à réunir dans une requête de synthèse groupée.
Choisir le client comme colonne de regroupement produit un rapport sur les clients plutôt que sur les commandes individuelles.
Colonne nue
Une colonne nue est une colonne sélectionnée qui n’est ni une colonne de regroupement ni placée dans un agrégat d’une requête d’agrégation.
SQLite peut afficher un client à côté d’un total régional même si plusieurs clients ont contribué au total de cette région.
Combinaison distincte
Une combinaison distincte est un ensemble unique de valeurs dans les colonnes sélectionnées, traité comme une ligne dans un résultat distinct.
East/Ana et East/Dara sont des paires distinctes lorsqu’un rapport liste les combinaisons région-client distinctes.
Comparaison sans arrondi
Une comparaison sans arrondi teste la valeur calculée initiale, même lorsque le résultat sélectionné en affiche une version arrondie.
Une moyenne affichée sous la forme 86,67 peut ne pas satisfaire HAVING AVG(amount) >= 86.67 si sa valeur exacte est inférieure.
Comptage conditionnel
Un comptage conditionnel ne compte que les lignes qui remplissent une condition choisie, souvent en faisant renvoyer NULL aux lignes non correspondantes dans COUNT.
COUNT(CASE WHEN amount >= 100 THEN 1 END) compte les commandes importantes en ignorant les résultats NULL des lignes non correspondantes.
Condition sur les groupes
Une condition sur les groupes teste une propriété d’un groupe calculé, par exemple pour savoir si son effectif ou sa moyenne atteint un seuil donné.
Un minimum de trois commandes par mois est une condition sur les groupes, car il faut connaître le nombre mensuel calculé.
Condition sur les lignes
Une condition sur les lignes peut être évaluée pour un enregistrement en entrée, par exemple pour savoir si sa date appartient à une plage ou si son montant atteint un seuil.
Le test amount >= 60 peut conserver une commande de East tout en en retirant une autre, avant qu’une synthèse régionale existe.
COUNT(*)
COUNT(*) est la forme d’agrégat qui compte toutes les lignes en entrée, y compris celles dont une ou plusieurs colonnes contiennent des valeurs manquantes.
Une table de huit commandes donne COUNT(*) égal à huit, même si aucune région n’est enregistrée pour une commande.
COUNT(column)
COUNT(column) compte les lignes ayant une valeur non NULL dans la colonne indiquée ; il inclut les valeurs répétées et les zéros enregistrés.
COUNT(discount) inclut une commande dont la remise vaut zéro, mais exclut une commande dont la remise vaut NULL.
COUNT(DISTINCT column)
COUNT(DISTINCT column) compte les différentes valeurs non NULL d’une colonne, chaque valeur enregistrée répétée n’étant comptée qu’une fois.
Utilise COUNT(DISTINCT customer) pour obtenir le nombre de clients nommés, même si certains passent plusieurs commandes.
Critère de départage
Un critère de départage est une clé de tri supplémentaire qui donne aux lignes un ordre reproductible lorsque leurs valeurs de tri précédentes sont égales.
ORDER BY total DESC, customer donne un ordre stable aux totaux par client ex aequo avant l’application d’une limite.

D

Dépendance fonctionnelle
Une dépendance fonctionnelle signifie qu’une valeur en détermine une autre, comme la clé primaire d’une commande qui détermine le client de cette commande.
PostgreSQL peut sélectionner le client lorsque le regroupement comprend la clé primaire de la table des commandes.
Détection des doublons
La détection des doublons trouve les valeurs répétées en regroupant les enregistrements selon ces valeurs et en conservant les groupes dont l’effectif dépasse un.
Un regroupement par client avec HAVING COUNT(*) > 1 identifie les clients ayant plusieurs enregistrements de commandes.
DISTINCT
DISTINCT supprime les valeurs ou les lignes en double à l’étape où il est appliqué, par exemple dans un agrégat ou dans la liste de sortie.
SUM(DISTINCT quantity) additionne chaque valeur de quantité une fois : des ventes réelles répétées peuvent donc être exclues du total.
Division entière
La division entière divise des opérandes entiers et supprime la partie fractionnaire dans SQLite, PostgreSQL et SQL Server.
Dans SQLite, la division de 19 articles par huit commandes avec des opérandes entiers donne 2 au lieu de la moyenne de 2,375.

E

Entrée entièrement NULL
Une entrée entièrement NULL comporte des lignes mais aucune valeur enregistrée pour l’expression agrégée : COUNT(x) vaut donc zéro.
Quatre commandes dont les remises sont inconnues donnent COUNT(*) égal à quatre et COUNT(discount) égal à zéro lorsqu’un filtre ne sélectionne que ces commandes.
Entrée vide
Une entrée vide est un ensemble sans aucune ligne entrant dans un calcul, par exemple lorsqu’une condition WHERE ne trouve aucun enregistrement correspondant.
Un comptage sans regroupement des commandes de South renvoie zéro lorsque toutes les commandes de la table appartiennent à d’autres régions.
Expression d’agrégation
Une expression d’agrégation applique une fonction de synthèse à une colonne ou à un calcul sur les lignes, par exemple pour additionner le produit de la quantité par le prix de chaque ligne.
SUM(amount - discount) évalue la soustraction pour chaque ligne avant d’additionner les résultats non NULL.
Expression de regroupement
Une expression de regroupement calcule une valeur de regroupement à partir de chaque ligne, comme un mois du calendrier ou une catégorie attribuée par CASE.
Une expression année-mois réunit les commandes de février tout en les distinguant de celles de février d’une autre année.

É

Écart d’arrondi
Un écart d’arrondi est une différence causée par la réduction de la précision, par exemple lorsque la somme des parties arrondies n’est plus égale au total arrondi.
Trois parts égales exprimées en pourcentage et affichées à une décimale totalisent 99,9 %, bien que les parts exactes couvrent 100 %.

F

Fonction d’agrégation
Une fonction d’agrégation combine les valeurs de plusieurs lignes en entrée en un seul résultat, comme un effectif, une somme, une moyenne ou une valeur extrême.
Un rapport des ventes utilise SUM(amount) pour transformer de nombreux montants de commande en un seul total pour la période sélectionnée.

G

Granularité
La granularité d’un rapport correspond à ce que représente une ligne de résultat, par exemple un client ou un mois, et détermine le regroupement nécessaire.
Un rapport avec une ligne par client nécessite des mesures au niveau du client, même si la table source enregistre des commandes.
GROUP BY
GROUP BY est la clause qui rassemble les lignes en entrée selon les valeurs communes d’une colonne ou d’une expression afin que les agrégats s’exécutent une fois par groupe.
GROUP BY region permet à une même requête de calculer un nombre de commandes et un total des montants distincts pour chaque région.
Groupe NULL
Un groupe NULL contient les lignes dont la valeur de regroupement est manquante ; SQL les rassemble dans un seul groupe de résultat.
Plusieurs commandes sans région partagent un total qui peut être affiché avec un libellé tel que « Sans région ».

H

HAVING
HAVING est la clause qui filtre les groupes selon leurs valeurs de regroupement ou leurs agrégats calculés, une fois que ces agrégats existent.
HAVING SUM(amount) > 200 conserve les régions selon leur total, sans retirer les petites commandes des groupes conservés.

I

IS NULL
IS NULL est un test SQL qui est vrai lorsqu’une valeur est manquante et permet de sélectionner ou de compter explicitement les enregistrements dont la valeur est manquante.
WHERE region IS NULL sélectionne les commandes dont la région n’a pas été enregistrée, comme une commande d’un client nommé Eli.

M

Mesure
Une mesure est la quantité qu’un rapport calcule, comme un effectif, un total ou une moyenne, au niveau de détail choisi pour ce rapport.
Un rapport mensuel des commandes peut utiliser le nombre de commandes et le montant moyen comme deux mesures de la même population mensuelle.
MIN et MAX
MIN et MAX sont des agrégats qui trouvent les plus petites et les plus grandes valeurs non NULL en entrée selon les règles de comparaison de la base de données.
MIN(order_date) trouve la date la plus ancienne lorsque la colonne contient des dates ou des dates au format texte ISO uniforme.
Moyenne par client
Une moyenne par client fait contribuer une fois le total de chaque client, ce qui diffère du calcul de la moyenne de tous les montants des commandes individuelles.
Lorsque cinq clients passent huit commandes totalisant 780, leur moyenne par client est de 156, alors que la moyenne des huit commandes est de 97,5.

N

Nombre à virgule flottante
Un nombre à virgule flottante stocke une approximation binaire de nombreuses valeurs décimales : certains calculs peuvent donc afficher de petits écarts d’arrondi.
Une addition en DOUBLE PRECISION dans PostgreSQL peut afficher 0.30000000000000004 là où le calcul décimal exact donne 0.3.
NULL
NULL indique une valeur SQL manquante ou inconnue ; un calcul arithmétique avec NULL produit NULL, qui est différent de zéro ou d’une chaîne vide.
Une remise inconnue peut rendre amount - discount égal à NULL, ce qui conduit SUM à ignorer la valeur calculée de cette ligne.
NULLIF
NULLIF renvoie NULL lorsque ses deux arguments sont égaux et renvoie sinon son premier argument, ce qui est utile pour les diviseurs nuls.
NULLIF(COUNT(*), 0) rend NULL le dénominateur d’un rapport vide, ce qui évite une erreur de division par zéro dans PostgreSQL.
NUMERIC et DECIMAL
NUMERIC et DECIMAL sont des types décimaux exacts dans PostgreSQL ; dans SQLite, ces noms donnent une affinité sans stockage décimal exact.
Pour des totaux monétaires exacts dans SQLite, les centimes entiers évitent de dépendre de valeurs fractionnaires stockées sous forme d’approximations binaires.

O

ONLY_FULL_GROUP_BY
ONLY_FULL_GROUP_BY est un mode MySQL qui rejette les expressions groupées contenant des valeurs non regroupées et non déterminées par le regroupement.
MySQL rejette normalement la sélection d’un client arbitraire lorsque la requête regroupe les commandes uniquement par région.
Opérande décimal
Un opérande décimal est une entrée numérique qui permet à un calcul de conserver un résultat fractionnaire lorsqu’elle est introduite avant une division entière.
Multiplier la somme par 1,0 avant la division conserve la partie fractionnaire d’une moyenne construite à partir de totaux.
ORDER BY
ORDER BY est la clause qui demande un ordre de sortie défini, notamment pour trier les lignes groupées selon un agrégat ou son alias.
ORDER BY total DESC liste d’abord les totaux de groupes les plus élevés après le calcul de chaque groupe.
Ordre logique d’une requête
L’ordre logique d’une requête décrit les étapes qui définissent son résultat, notamment le filtrage des lignes avant les calculs sur les groupes.
Suivre WHERE avant GROUP BY explique pourquoi le retrait des petites commandes modifie ensuite la moyenne d’une région.

P

Pourcentage au sein du groupe
Un pourcentage au sein du groupe mesure la part d’un sous-ensemble dans son propre groupe, en utilisant la population complète de ce groupe comme dénominateur.
Une commande importante parmi trois commandes de East représente environ 33,3 % des commandes de East, quels que soient les effectifs des autres régions.

R

Rapprochement
Le rapprochement vérifie que la somme des effectifs et des totaux des groupes correspond aux mesures équivalentes sans regroupement sur la même population filtrée.
Exécute d’abord la requête sans HAVING afin que les groupes exclus n’expliquent pas une différence entre le rapport et le total en entrée.
Règle de regroupement
La règle de regroupement exige que chaque valeur sélectionnée ait un sens défini pour son groupe, grâce au regroupement ou à l’agrégation.
Une région contenant plusieurs clients ne peut pas fournir un seul nom de client simple, sauf si la requête précise comment le choisir.
Regroupement sur plusieurs colonnes
Un regroupement sur plusieurs colonnes forme un groupe pour chaque combinaison de valeurs de regroupement effectivement présente dans les lignes en entrée conservées.
Un regroupement par région et par client donne des résultats distincts pour Ana et Dara dans East tout en gardant les commandes d’Ana ensemble.
ROUND
ROUND est une fonction qui arrondit une valeur numérique, son second argument indiquant normalement le nombre de chiffres après la virgule.
ROUND(AVG(amount), 2) arrondit la moyenne calculée à deux décimales, sans modifier le calcul effectué auparavant.

S

Somme conditionnelle
Une somme conditionnelle additionne les montants des lignes correspondantes, généralement avec une expression CASE qui renvoie zéro pour les autres lignes.
Une somme des commandes importantes renvoie le montant correspondant lui-même depuis CASE ; renvoyer 1 compterait les commandes.
SUM
SUM est une fonction d’agrégation qui additionne les valeurs numériques non NULL d’une colonne ou d’une expression sur les lignes en entrée.
SUM(quantity * unit_price) totalise les chiffres d’affaires des lignes après multiplication de chaque quantité par le prix correspondant.

T

Table dérivée
Une table dérivée est le résultat d’une requête utilisée dans FROM, ce qui permet à une seconde requête de synthétiser les lignes créées par la première.
Une requête interne crée des totaux par client ; une requête externe utilise ces totaux en entrée pour calculer leur moyenne.
Troncature
La troncature supprime des chiffres fractionnaires sans arrondir ; PostgreSQL propose TRUNC et SQLite tronque lors d’une conversion en entier.
TRUNC(2.97, 1) donne 2.9 dans PostgreSQL, tandis que ROUND(2.97, 1) donne 3.0 pour ce décimal exact.

V

Valeur à mi-chemin
Une valeur à mi-chemin se situe exactement entre deux résultats arrondis possibles ; le résultat choisi dépend du type de nombre et de la règle d’arrondi.
Dans PostgreSQL, l’arrondi exact de type NUMERIC transforme 2,5 en 3 et -2,5 en -3, en éloignant les deux valeurs à mi-chemin de zéro.

W

WHERE
WHERE est la clause qui filtre les lignes individuelles en entrée avant le regroupement et détermine les enregistrements qui contribuent aux synthèses ultérieures.
Un rapport limité aux commandes de 2026 utilise une condition de date dans WHERE avant de calculer les totaux mensuels.

À propos de cette unité

Par StudeliSignaler une erreur

Crée ton propre Matériel d'Étude

Transforme tes notes, diapos et documents en Guides d'Étude, Questions Pratiques, Flashcards et 6 autres outils.

Commencer