Colonnes calculées SQL, fonctions et CASE
DébutantUnité 3 sur 6 de la formation Formation : SQL : requêtes SELECT, jointures et agrégation
Ce que tu vas apprendre
- Calcule de nouvelles valeurs pour chaque ligne à l’aide d’opérations arithmétiques et de fonctions, donne des noms explicites aux résultats et évite que les types de données ne modifient la réponse.
- Calculer de nouvelles colonnes et les nommer avec des aliasÉcris des expressions dans la liste SELECT, nomme les résultats avec AS et repère où ces noms peuvent être utilisés dans une requête.
- Calculer avec les opérateurs arithmétiques et les fonctions numériquesUtilise +, -, *, / et % dans le bon ordre, évite les surprises liées à la division entière et arrondis les résultats avec ROUND et les fonctions associées.
- Convertir des valeurs d’un type de données à un autreReconnais le type de chaque valeur, convertis-la explicitement avec CAST et repère les conversions automatiques qui modifient le tri, les comparaisons et les résultats.
- Calculer de nouvelles colonnes et les nommer avec des alias
- Prévois l’effet de NULL sur les calculs, les comparaisons et les filtres, et remplace ou crée délibérément des valeurs manquantes.
- Prévoir le comportement de NULL dans les calculs et les conditionsExplique ce que signifie NULL, comment il se propage dans les expressions et pourquoi une condition qui rencontre NULL n’est ni vraie ni fausse.
- Remplacer et créer des valeurs manquantes avec COALESCE et NULLIFComble les valeurs manquantes avec COALESCE, transforme les zéros et les valeurs factices en NULL avec NULLIF et choisis des valeurs de remplacement qui conservent le sens des données.
- Prévoir le comportement de NULL dans les calculs et les conditions
- Concatène, nettoie, mesure et découpe des valeurs textuelles pour obtenir des noms, des adresses e-mail et des codes cohérents et utilisables.
- Concaténer et nettoyer des valeurs textuellesConcatène du texte, change la casse, supprime les espaces en début et en fin de chaîne et remplace des caractères, puis imbrique ces fonctions pour nettoyer des données saisies de façon irrégulière.
- Mesurer un texte et en extraire des partiesCompte les caractères, trouve où apparaît un caractère et découpe des parties de texte à l’aide de positions qui commencent à 1.
- Concaténer et nettoyer des valeurs textuelles
- Écris et lis correctement des valeurs de date, décompose-les et mets-les en forme, puis effectue des calculs avec des jours, des mois et des durées.
- Écrire, stocker et lire des valeurs de date et d’heureReconnais les types de date et d’heure, écris les dates au format ISO sans ambiguïté, convertis du texte en dates et obtiens la date et l’heure actuelles.
- Extraire et mettre en forme des parties de datesExtrais l’année, le mois ou le jour de la semaine, regroupe les dates par période et transforme-les en texte lisible.
- Calculer avec des dates et filtrer des plages de datesAjoute des jours et des mois, mesure le temps entre deux dates et écris des filtres qui incluent toutes les lignes d’une période.
- Écrire, stocker et lire des valeurs de date et d’heure
- Transforme des conditions en libellés, en catégories et en ordres de tri personnalisés avec CASE, puis combine-le avec les autres fonctions dans des requêtes de rapport complètes.
- Répartir des lignes en catégories avec un CASE recherchéÉcris CASE WHEN … THEN … ELSE … END, ordonne les conditions pour placer chaque ligne dans le bon groupe et traite les valeurs limites et les NULL.
- Utiliser le CASE simple et employer CASE dans toute une requêteTraduis des codes avec le CASE simple, construis des indicateurs et des ordres de tri personnalisés, et reconnais les formes plus courtes proposées par d’autres bases de données.
- Combiner des fonctions dans une requête de rapport complèteConstruis un rapport avec plusieurs colonnes calculées étape par étape, imbrique correctement les fonctions et vérifie chaque colonne à partir de lignes calculées à la main.
- Répartir des lignes en catégories avec un CASE recherché
Colonnes calculées SQL : cours
1Créer des colonnes calculées avec des expressions et des alias
Les colonnes calculées transforment les valeurs déjà présentes dans une ligne en réponses utiles : le montant d’une ligne, une remise ou un pourcentage de changement. Des alias explicites rendent ces résultats lisibles, tandis que les parenthèses et les types de données déterminent ce que SQL calcule réellement. Tu construiras des expressions par petites étapes, verras pourquoi la division entière peut supprimer une fraction et choisiras des conversions explicites lorsque la forme stockée ne convient pas à l’opération.
1.1 Calculer de nouvelles colonnes et les nommer avec des alias
Une colonne de résultat peut afficher une valeur qui n’est stockée nulle part dans la table. SQL la calcule à partir de la ligne courante. Une expression combine des colonnes, des valeurs fixes, des opérateurs et des appels de fonctions.
Calculer une valeur pour chaque ligne
SELECT order_id,
quantity * unit_price AS line_total
FROM orders;
Pour une quantité de 3 et un prix unitaire de 12,50, la nouvelle colonne affiche 37.5. Chaque ligne fournit sa propre quantité et son propre prix. La requête laisse les colonnes stockées inchangées. Une fonction monoligne, comme ROUND(unit_price, 0), renvoie aussi une valeur par ligne d’entrée. L’ajouter à la liste SELECT ne combine pas les lignes. Une fonction d’agrégation comme SUM ou AVG calcule quant à elle une valeur pour un groupe.
Le nom après AS est un alias de colonne : un en-tête pour le résultat. Sans lui, SQLite utilise le texte de l’expression comme en-tête ; PostgreSQL utilise ?column? pour cette expression arithmétique. AS est facultatif, mais permet de distinguer plus facilement un nom d’une virgule manquante.
Choisir les noms et les guillemets
Utilise un nom simple comme line_total : des lettres, des chiffres et des tirets bas, en commençant par une lettre. Un nom contenant un espace ou correspondant à un mot réservé doit être entouré de guillemets doubles : AS "Line Total" ou AS "order". Les apostrophes délimitent les valeurs textuelles, comme 'Boston'. MySQL accepte aussi les accents graves pour les noms, et SQL Server accepte les crochets.
PostgreSQL convertit en minuscules les noms sans guillemets : AS LineTotal produit linetotal. Les guillemets doubles conservent la casse dans AS "LineTotal". SQLite conserve un alias tel qu’il est saisi. Les noms en minuscules séparées par des tirets bas conviennent aux deux.
Utiliser un alias à la bonne étape
L’ordre logique est FROM, WHERE, SELECT, puis ORDER BY. La table est choisie et les lignes sont filtrées avant que les expressions de sortie ne reçoivent leurs alias. Le tri a lieu ensuite.
SELECT order_id,
quantity * unit_price AS line_total
FROM orders
WHERE quantity * unit_price > 100
ORDER BY line_total DESC;
ORDER BY peut utiliser line_total. Le SQL standard, PostgreSQL et MySQL ne peuvent pas utiliser ce nouvel alias dans WHERE ; répète l’expression à cet endroit. SQLite accepte un alias dans WHERE comme extension, mais cette forme échouera si elle est transférée vers PostgreSQL.
Un nouvel alias n’est pas non plus disponible pour une autre expression dans la même liste SELECT. Après unit_price * 1.08 AS with_tax, écrire with_tax - unit_price AS tax échoue si la table ne possède pas de colonne with_tax. Écris plutôt unit_price * 1.08 - unit_price AS tax.
Diagnostiquer un résultat surprenant
SELECT first_name last_name FROM customers; est du SQL valide. Cette requête affiche une colonne de prénoms avec l’alias last_name. Pour extraire les deux colonnes, écris SELECT first_name, last_name FROM customers;. Une virgule manquante peut donc produire un résultat trompeur sans erreur.
Pour vérifier rapidement une expression, une table est inutile : SELECT 19.99 * 3 AS total; renvoie 59.97 dans SQLite et PostgreSQL. Avant Release 23, Oracle exige FROM DUAL pour cette requête ; Release 23 et les versions ultérieures autorisent aussi SELECT sans FROM.
Points clés
- Une colonne calculée calcule une valeur pour chaque ligne sans modifier les données stockées.
- Une fonction monoligne conserve les lignes ; un agrégat combine les valeurs d’un groupe.
- Utilise des guillemets doubles pour les noms qui doivent être délimités et des apostrophes pour les valeurs textuelles.
- ORDER BY peut utiliser un alias de sortie ; répète l’expression dans une clause WHERE portable.
- Un nouvel alias n’est pas disponible ailleurs dans la même liste SELECT.
- Une virgule manquante peut transformer le nom de colonne suivant en alias.
1.2 Calculer avec les opérateurs arithmétiques et les fonctions numériques
Les expressions arithmétiques transforment des quantités brutes en montants, en taux et en différences. Les opérateurs sont +, -, *, / et % ; le modulo donne le reste de la division.
Maîtriser l’ordre des calculs
La multiplication, la division et le modulo viennent avant l’addition et la soustraction. Les opérateurs de même priorité s’exécutent de gauche à droite. Ainsi, 10 + 3 * 2 donne 16, tandis que (10 + 3) * 2 donne 26.
Pour une quantité de 3, un prix unitaire de 12,50 et un pourcentage de remise de 10 :
quantity * unit_price * (1 - discount_pct / 100.0)
D’abord, 10 / 100.0 donne 0.1. Les parenthèses donnent la fraction payée, 0.9. Le montant brut est 37.5, donc le montant net est 33.75. Sans parenthèses, quantity * unit_price * 1 - discount_pct / 100.0 soustrait 0.1 de 37.5 et donne 37.4.
Conserver les fractions pendant la division
Dans SQLite, PostgreSQL et SQL Server, la division de deux entiers supprime la partie fractionnaire par troncation vers zéro : 7 / 2 donne 3, et -7 / 2 donne -3. MySQL et Oracle donnent un résultat décimal pour /. Dans SQLite et PostgreSQL, rends un opérande décimal avant de diviser : 7 / 2.0, 7 * 1.0 / 2 ou CAST(7 AS REAL) / 2 donne 3.5. Avec CAST(7 / 2 AS REAL), la conversion arrive trop tard et donne 3.0.
Pour une hausse de 80 à 92, (92 - 80) * 100.0 / 80 donne 15.0 pour cent. Diviser d’abord la différence entière par 80 fait perdre la fraction. Le modulo conserve le reste : 135 / 60 vaut 2 heures et 135 % 60 vaut 15 minutes. Dans SQLite et PostgreSQL, -7 % 3 donne -1 ; le reste prend le signe de l’opérande de gauche. Oracle écrit MOD(17, 5) à la place de %.
Un diviseur nul produit une erreur dans PostgreSQL et SQL Server ; SQLite et MySQL renvoient NULL. amount / NULLIF(divisor, 0) fait renvoyer NULL dans le cas d’un diviseur nul sur ces systèmes.
Arrondir ou choisir un entier
ROUND(x, n) arrondit à n décimales. Une lampe vendue 24,00 et coûtant 15,50 dégage un bénéfice de 8.5. ROUND((price - cost) / price * 100, 1) donne une marge de 35.4 pour cent. PostgreSQL accepte un nombre de décimales négatif : ROUND(1234.5678, -2) donne 1200 ; SQLite traite ce nombre comme zéro et donne 1235.0.
| Fonction | Signification | Exemple |
|---|---|---|
ABS | Distance à zéro | ABS(-4.2) donne 4.2 |
CEIL | Plus petit entier supérieur ou égal à la valeur | CEIL(4.1) donne 5 |
FLOOR | Plus grand entier inférieur ou égal à la valeur | FLOOR(-4.1) donne -5 |
TRUNC | Supprime la partie fractionnaire par troncation vers zéro | TRUNC(42.8) donne 42 |
PostgreSQL fournit ces fonctions. SQLite fournit ABS ; CEIL, FLOOR et TRUNC exigent une version compilée avec les fonctions mathématiques, disponibles à partir de la version 3.35.
Adapter la précision aux données
ROUND dans SQLite et ROUND pour le type numeric de PostgreSQL arrondissent les valeurs exactement à mi-chemin en s’éloignant de zéro : ROUND(-2.5) donne -3. Dans PostgreSQL, l’arrondi des nombres à virgule flottante arrondit généralement les valeurs à mi-chemin à l’entier pair le plus proche ; sa fonction ROUND à deux arguments exige numeric, utilise donc ROUND(CAST(x AS numeric), 2) pour une colonne à double précision.
Les nombres à virgule flottante représentent de nombreuses fractions décimales de façon approximative. Dans SQLite, 0.1 + 0.2 = 0.3 peut être faux et ROUND(2.675, 2) peut renvoyer 2.67. Les littéraux décimaux de PostgreSQL utilisent le type exact numeric. Pour des montants exacts, utilise NUMERIC/DECIMAL dans PostgreSQL ou des centimes entiers dans SQLite. Déclarer DECIMAL dans SQLite ne crée pas de stockage décimal exact. Garde toutes les décimales pendant les calculs et arrondis pour l’affichage.
Points clés
- Les parenthèses déterminent quels montants sont combinés avant une multiplication ou une division.
- Convertis un opérande avant la division entière ; convertir le résultat ne peut pas restaurer les chiffres perdus.
- Le modulo renvoie un reste, comme les minutes qui restent après les heures entières.
- ROUND, FLOOR, CEIL et TRUNC traitent une valeur fractionnaire de différentes façons.
- L’arrondi des nombres à virgule flottante et les fonctions numériques disponibles dépendent du type et de la base de données.
- Utilise un stockage numérique exact dans PostgreSQL ou des centimes entiers dans SQLite pour les montants exacts.
- NULLIF peut faire qu’un diviseur nul produise NULL au lieu d’une erreur.
1.3 Convertir des valeurs d’un type de données à un autre
Le type de données d’une valeur influe sur les opérations arithmétiques, les comparaisons et le tri. Le nombre 42 est différent du texte '42', même lorsqu’une grille de résultats les affiche de la même façon.
Convertir explicitement une valeur
Parmi les types courants figurent INTEGER pour les entiers, NUMERIC ou DECIMAL pour les décimaux exacts dans PostgreSQL, REAL ou double precision pour les nombres approximatifs, TEXT ou VARCHAR pour le texte, ainsi que DATE, TIME, TIMESTAMP et BOOLEAN lorsqu’ils sont pris en charge.
SELECT CAST('42' AS INTEGER) AS number_value,
CAST(42 AS TEXT) AS text_value;
CAST(expression AS type) fait partie du SQL standard. Le premier résultat est un nombre ; le second est du texte. PostgreSQL accepte aussi '42'::integer. Convertir NULL donne toujours NULL.
Pour une division décimale dans SQLite, écris CAST(quantity AS REAL) / 4 ; dans PostgreSQL, écris CAST(quantity AS NUMERIC) / 4. Une quantité de 7 donne 1.75. Dans SQLite, CAST(7 AS NUMERIC) / 2 donne toujours 3 : NUMERIC laisse cette valeur entière stockée comme un entier. REAL est le type de conversion adapté à cet usage dans SQLite.
Comprendre l’effet d’une conversion en entier
| Entrée et conversion | SQLite | PostgreSQL |
|---|---|---|
CAST(3.9 AS INTEGER) | 3 | 4 |
CAST(-3.9 AS INTEGER) | -3 | -4 |
CAST('abc' AS INTEGER) | 0 | Erreur |
SQLite supprime la partie fractionnaire par troncation vers zéro. PostgreSQL arrondit une valeur numérique à l’entier le plus proche. Utilise d’abord ROUND, TRUNC, FLOOR ou CEIL lorsque la règle choisie compte. PostgreSQL refuse un texte qui n’est pas un nombre valide. SQLite lit une partie numérique initiale : '12abc' devient 12 et '12.5' devient 12 lors d’une conversion en INTEGER. Un zéro obtenu après une conversion dans SQLite ne prouve donc pas que le texte d’origine était un zéro valide. TRY_CAST dans SQL Server renvoie NULL lorsqu’une conversion échoue.
Distinguer les quantités des identifiants
Le texte est trié caractère par caractère. Les chaînes '9', '10' et '100' sont triées dans l’ordre '10', '100', '9'. Pour classer de véritables quantités numériques conservées sous forme de texte, utilise ORDER BY CAST(code AS INTEGER) après t’être assuré que ce sont des nombres valides.
Un code postal américain comme '02134' est un identifiant. Le convertir donne 2134 et fait perdre le premier zéro. Les numéros de téléphone doivent aussi être du texte : leurs chiffres servent à identifier quelque chose, plutôt qu’à décrire une quantité à additionner ou dont calculer la moyenne.
Reconnaître les conversions automatiques
SQLite et PostgreSQL convertissent tous deux le nombre en texte dans 'Order #' || 42, ce qui produit 'Order #42'. Tous deux évaluent aussi le littéral entre apostrophes dans '5' + 3 comme un nombre. Dans PostgreSQL, ce littéral a initialement un type non fixé ; une colonne TEXT n’a pas la même liberté. Ajouter 3 à une colonne TEXT échoue : convertis donc explicitement la colonne.
SQLite attribue aux colonnes une préférence de type, appelée affinité de type, et peut conserver différents types de valeurs dans une même colonne ordinaire. typeof(42), typeof(4.2), typeof('42') et typeof(NULL) indiquent 'integer', 'real', 'text' et 'null'. SQLite n’a pas de type DATE dédié : CAST('2026-03-14' AS DATE) donne 2026. Utilise date('2026-03-14') avec ses fonctions de date.
Oracle fournit TO_NUMBER, TO_CHAR et TO_DATE. TO_CHAR et TO_DATE dans PostgreSQL prennent des modèles de format comme 'MM/DD/YYYY'. CONVERT dans SQL Server utilise un code de style numérique : CONVERT(date, '03/14/2026', 101) lit le format de date américain.
Points clés
- CAST convertit explicitement une valeur dans le type demandé ; NULL reste NULL.
- SQLite tronque les valeurs numériques converties en entiers, tandis que PostgreSQL les arrondit.
- SQLite peut convertir un texte numérique invalide en un nombre partiel ou en zéro.
- Conserve les codes postaux américains et les numéros de téléphone sous forme de texte pour préserver leur identité.
- Le tri des textes et celui des nombres peuvent donner des ordres différents.
2Gérer les valeurs manquantes avec la logique de NULL et COALESCE
Une valeur manquante peut modifier un calcul ainsi que les lignes conservées par un filtre. Pour comprendre NULL, il faut suivre à la fois les données et la condition qui les utilise. Tu distingueras une valeur manquante de zéro et d’une chaîne vide, suivras TRUE, FALSE et UNKNOWN dans une requête et choisiras des valeurs de repli qui préservent le sens d’un rapport. COALESCE et NULLIF te permettront ensuite de combler des valeurs manquantes ou d’en créer délibérément.
2.1 Prévoir le comportement de NULL dans les calculs et les conditions
NULL indique une valeur manquante ou inconnue. Une cellule de résultat vide peut afficher NULL, mais NULL n’est pas une valeur ordinaire que l’on compare avec =.
Suivre une entrée manquante dans une expression
Zéro est un nombre connu. La chaîne vide '' est une chaîne connue sans caractère. Le texte 'N/A' est un libellé enregistré. NULL indique qu’aucune valeur n’est disponible. Oracle traite la chaîne vide comme NULL ; SQLite et PostgreSQL les distinguent.
La plupart des opérations arithmétiques et des fonctions transmettent une entrée manquante sous la forme NULL. Avec un salaire de 50 000 et une prime NULL, salary + bonus donne NULL. Le total est inconnu parce que la prime est inconnue. UPPER(NULL), ROUND(NULL, 2) et 'Ana ' || NULL renvoient aussi NULL dans SQLite et PostgreSQL.
Tester directement NULL
bonus = NULL, bonus <> NULL et même NULL = NULL produisent UNKNOWN. On ne sait pas si deux valeurs manquantes sont égales. Utilise bonus IS NULL ou bonus IS NOT NULL. Ces tests renvoient toujours TRUE ou FALSE.
Les conditions SQL ont trois résultats possibles : TRUE, FALSE et UNKNOWN. SQLite affiche TRUE sous la forme 1, FALSE sous la forme 0 et UNKNOWN sous la forme NULL.
| Condition | Résultat | Raison |
|---|---|---|
FALSE AND UNKNOWN | FALSE | Une condition fausse suffit à rendre AND faux |
TRUE AND UNKNOWN | UNKNOWN | La deuxième condition reste indéterminée |
TRUE OR UNKNOWN | TRUE | Une possibilité vraie suffit à rendre OR vrai |
FALSE OR UNKNOWN | UNKNOWN | La possibilité restante reste indéterminée |
NOT UNKNOWN | UNKNOWN | Inverser une valeur inconnue ne la détermine pas |
Comprendre les lignes conservées par WHERE
WHERE ne conserve que TRUE. FALSE et UNKNOWN excluent tous deux la ligne. Pour les primes 1 000, 0, NULL, 2 500 et NULL, WHERE bonus < 1000 ne conserve que le zéro. WHERE bonus >= 1000 conserve 1 000 et 2 500. Ces filtres couvrent trois lignes, et non cinq. WHERE NOT (bonus < 1000) ne conserve aussi que les deux primes connues d’au moins 1 000.
Le même problème concerne <>. Avec les villes Boston, Denver, NULL, Boston et Austin, WHERE city <> 'Boston' conserve Denver et Austin. Inclus explicitement la ville inconnue :
WHERE city <> 'Boston' OR city IS NULL
Cette condition conserve trois lignes. NOT ne réintègre pas automatiquement les valeurs manquantes.
Surveiller les listes et les comparaisons
3 IN (1, 2, NULL) vaut UNKNOWN : l’élément manquant pourrait être 3. Pour x NOT IN (1, 2, NULL), une valeur correspondante ne passe pas le test NOT IN et toute valeur sans correspondance donne UNKNOWN. Dans une clause WHERE, cette liste fixe ne conserve aucune ligne. Supprime tout NULL involontaire d’une liste d’exclusion avant de l’utiliser.
Pour une égalité qui considère deux NULL comme égaux, utilise a IS NOT DISTINCT FROM b. Son contraire, a IS DISTINCT FROM b, vaut TRUE lorsqu’une valeur est NULL et que l’autre ne l’est pas ; deux NULL ne sont pas distincts. PostgreSQL et SQLite à partir de la version 3.39 prennent en charge ces formes. SQLite possède aussi IS et IS NOT ; MySQL écrit l’égalité sûre avec NULL sous la forme <=>.
Le placement des NULL par défaut diffère selon la base : SQLite place NULL en premier dans l’ordre croissant ; PostgreSQL le place en dernier. Précise le placement lorsqu’il compte : ORDER BY bonus DESC NULLS LAST place les primes connues par ordre décroissant et les primes manquantes à la fin.
Points clés
- NULL indique une valeur manquante ou inconnue, et non zéro ou une chaîne vide.
- Les comparaisons avec NULL produisent UNKNOWN ; teste les valeurs manquantes avec IS NULL.
- WHERE ne conserve que TRUE : NOT et <> ne réintègrent donc pas les lignes dont le résultat est inconnu.
- AND et OR ne peuvent déterminer un résultat inconnu que si l’autre condition décide du résultat.
- Un NULL dans une liste NOT IN empêche cette condition de valoir TRUE.
- IS NOT DISTINCT FROM considère deux NULL comme égaux.
- NULLS FIRST ou NULLS LAST rend le placement dans le tri explicite.
2.2 Remplacer et créer des valeurs manquantes avec COALESCE et NULLIF
Les valeurs manquantes ont parfois besoin d’une valeur de repli et doivent parfois rester manquantes. Ce choix fait partie du sens d’un rapport. COALESCE comble une valeur manquante ; NULLIF transforme une valeur factice correspondante en valeur manquante.
Choisir la première valeur disponible
COALESCE(a, b, ...) examine les arguments de gauche à droite et renvoie le premier qui n’est pas NULL. La fonction renvoie NULL si tous les arguments sont NULL.
SELECT COALESCE(mobile_phone, home_phone, 'no phone') AS contact
FROM customers;
Sans numéro de portable et avec le numéro fixe '555-0100', le contact est '555-0100'. Si aucun des deux numéros n’est enregistré, c’est 'no phone'. Un zéro connu ou une chaîne vide compte comme disponible : COALESCE ignore NULL, pas les valeurs qui semblent vides ou fausses.
Pour la rémunération, salary + COALESCE(bonus, 0) donne 50 000 lorsque le salaire est de 50 000 et que la prime vaut NULL. Cela convient si une prime manquante signifie qu’aucune prime n’a été versée. Une note de produit manquante ne signifie pas une note de zéro ; la remplacer inventerait une mauvaise note. Laisse ce nombre manquant ou crée un libellé textuel pour l’affichage.
Garder des types compatibles pour les valeurs de repli
PostgreSQL ne peut pas combiner l’entier rating et le texte 'not rated' dans un même résultat numérique. Convertis d’abord les notes connues en texte :
COALESCE(CAST(rating AS TEXT), 'not rated')
Une note de 4 s’affiche sous forme du texte '4' ; un NULL s’affiche sous la forme 'not rated'. SQLite accepte des arguments numériques et textuels mélangés, mais la sortie peut alors contenir différents types. Rends le type de résultat attendu explicite lorsque tu transfères une requête d’une base à une autre.
COALESCE fait partie du SQL standard et accepte au moins deux arguments. Les variantes courantes à deux arguments sont IFNULL dans SQLite et MySQL, ISNULL dans SQL Server et NVL dans Oracle.
Transformer une valeur factice en NULL
NULLIF(a, b) renvoie NULL si les arguments sont égaux ; sinon, la fonction renvoie le premier argument. NULLIF(0, 0) vaut NULL, tandis que NULLIF(5, 0) vaut 5.
Voici une expression utile pour calculer un taux :
orders * 100.0 / NULLIF(visits, 0) AS conversion_pct
Avec 12 commandes et 300 visites, le diviseur reste égal à 300 et le taux est 4.0. Avec zéro visite, le diviseur devient NULL et le taux devient NULL. PostgreSQL évite une erreur de division par zéro et le résultat indique correctement un taux indéfini. Remplacer ce taux par zéro exprimerait une autre affirmation.
Nettoyer les valeurs manquantes avant de fournir un libellé
COALESCE(NULLIF(phone, ''), 'unknown')
Le NULLIF intérieur transforme une chaîne vide en NULL. Le COALESCE extérieur attribue ensuite le libellé 'unknown' aussi bien à un NULL d’origine qu’à une chaîne vide. Un numéro de téléphone enregistré est conservé tel quel.
Pour un deuxième prénom facultatif, inclus l’espace qui le suit dans la valeur de repli :
first_name || ' ' || COALESCE(middle_name || ' ', '') || last_name
Un deuxième prénom NULL n’ajoute rien, ce qui produit 'Ana Lopez'. Un deuxième prénom 'Maria' ajoute 'Maria ', ce qui produit 'Ana Maria Lopez'.
Ces expressions ne modifient que le résultat de la requête. Elles laissent les valeurs d’origine stockées dans la table. Un filtre comme WHERE COALESCE(bonus, 0) = 0 regroupe les primes connues égales à zéro et les primes manquantes ; utilise-le donc lorsque ce sont les deux groupes recherchés.
Points clés
- COALESCE renvoie le premier argument qui n’est pas NULL, y compris un zéro connu ou une chaîne vide.
- Une valeur de repli doit exprimer le sens des données manquantes et avoir un type compatible.
- NULLIF renvoie NULL en cas d’égalité et son premier argument sinon.
- Utilise NULLIF autour d’un diviseur pour qu’un dénominateur nul produise NULL.
- Nettoie une valeur factice avec NULLIF avant d’appliquer une valeur de repli pour l’affichage avec COALESCE.
3Nettoyer, combiner et découper du texte avec les fonctions de chaînes
Le texte d’une table doit souvent être rendu utilisable : un nom complet, une adresse e-mail cohérente ou une partie de code. SQL peut concaténer et nettoyer des chaînes, compter leurs caractères et extraire la partie située avant ou après un séparateur. Tu suivras les positions des caractères à chaque étape et vérifieras l’effet des espaces, de la casse et de NULL sur le résultat. SQLite et PostgreSQL partagent de nombreuses fonctions, mais plusieurs noms et comportements diffèrent.
3.1 Concaténer et nettoyer des valeurs textuelles
SQL traite une valeur textuelle comme une chaîne de caractères. Les fonctions de texte peuvent construire un nom complet ou nettoyer une adresse e-mail pour la comparer. Leurs résultats apparaissent dans la requête ; le texte stocké reste inchangé.
Écrire et concaténer du texte
Les littéraux textuels utilisent des apostrophes. Pour inclure une apostrophe, double-la : 'O''Brien' représente « O'Brien ». Une paire d’apostrophes, '', est une chaîne vide.
SELECT first_name || ' ' || last_name AS full_name
FROM customers;
L’opérateur de concaténation || assemble les parties exactement telles qu’elles sont écrites. Avec 'Ana' et 'Lopez', le résultat est 'Ana Lopez'. Le littéral du milieu fournit l’espace ; la concaténation n’en insère pas automatiquement.
SQLite, PostgreSQL et Oracle utilisent ||. Dans MySQL, || signifie OR par défaut : utilise donc CONCAT. SQL Server utilise + et prend aussi en charge || à partir de 2025. Pour concaténer un identifiant numérique de commande, SQLite et PostgreSQL le convertissent en texte dans 'Order #' || order_id. Avec le + de SQL Server, convertis d’abord le nombre : 'Order #' + CAST(order_id AS VARCHAR(10)).
Choisir comment concaténer une partie manquante
Dans SQLite et PostgreSQL, un opérande NULL rend le résultat de || NULL. Oracle traite cette partie manquante comme une chaîne vide. CONCAT diffère aussi selon la base de données :
| Base de données | CONCAT('Ana', NULL, 'Lopez') |
|---|---|
| PostgreSQL, SQL Server, SQLite à partir de la version 3.44 | 'AnaLopez' |
| MySQL | NULL |
CONCAT dans Oracle prend exactement deux arguments. CONCAT_WS(' ', first_name, middle_name, last_name) place des espaces entre les parties qui ne sont pas NULL, donc un deuxième prénom manquant donne 'Ana Lopez'. SQLite a ajouté CONCAT et CONCAT_WS dans la version 3.44. Ignorer NULL ne supprime toutefois pas une chaîne vide.
Changer la casse et supprimer les espaces aux extrémités
UPPER('boston') donne 'BOSTON' ; LOWER produit des minuscules. INITCAP('ana LOPEZ') dans PostgreSQL donne 'Ana Lopez'. SQLite n’a pas INITCAP, et son changement de casse intégré ne modifie que les lettres de A à Z : UPPER('é') reste 'é' sans l’extension ICU. Le changement de casse dans PostgreSQL suit ses paramètres régionaux.
TRIM supprime les espaces aux deux extrémités ; LTRIM les supprime seulement au début et RTRIM seulement à la fin. TRIM(' New York ') donne 'New York', en conservant les deux espaces intérieurs. Pour supprimer x aux deux extrémités, SQLite écrit TRIM('xxBostonxx', 'x') ; PostgreSQL écrit TRIM(BOTH 'x' FROM 'xxBostonxx').
Remplacer des caractères et imbriquer les étapes de nettoyage
REPLACE('555-0100', '-', '') donne '5550100'. La fonction remplace chaque occurrence exacte. La casse compte : remplacer 'st' dans 'Main St' ne change rien, car 'St' comporte un S majuscule.
SELECT LOWER(TRIM(email)) AS email_clean
FROM customers;
Pour ' Ana@Example.COM ', TRIM produit d’abord 'Ana@Example.COM', puis LOWER produit 'ana@example.com'. L’imbrication signifie que la fonction la plus intérieure fournit l’entrée de la suivante.
La comparaison ordinaire de textes par égalité distingue par défaut les majuscules des minuscules dans SQLite et PostgreSQL. WHERE LOWER(TRIM(email)) = 'ana@example.com' peut trouver une correspondance avec une entrée dont la casse diffère et qui comporte des espaces aux extrémités. La collation par défaut de MySQL ignore la casse, et LIKE dans SQLite ignore la casse des lettres de A à Z, même si sa comparaison = par défaut ne l’ignore pas.
Points clés
- Utilise des apostrophes pour le texte et double toute apostrophe à l’intérieur d’un littéral.
- La concaténation assemble les parties exactes ; inclus explicitement les séparateurs.
- Le comportement de NULL diffère entre ||, CONCAT et les dialectes des bases de données.
- TRIM supprime les espaces aux extrémités, tandis que REPLACE modifie les caractères correspondants partout dans le texte.
- Les fonctions imbriquées s’exécutent de l’intérieur vers l’extérieur.
- Le changement de casse et les comparaisons qui en tiennent compte dépendent de la base de données et des paramètres régionaux.
3.2 Mesurer un texte et en extraire des parties
Les fonctions de texte repèrent et découpent des parties selon la position des caractères. En SQL, les positions commencent à 1 : le premier caractère est donc à la position 1. Une position trouvée et un nombre de caractères sont deux entrées différentes.
Mesurer et découper une chaîne
LENGTH('Boston') donne 6. Les espaces comptent : LENGTH(' Bo ') donne 4. Une chaîne vide a une longueur de 0 ; LENGTH(NULL) vaut NULL. Dans MySQL, LENGTH compte les octets : utilise donc CHAR_LENGTH pour compter les caractères. SQL Server utilise LEN, qui ignore les espaces en fin de chaîne.
SELECT SUBSTR('Boston', 1, 3) AS beginning,
SUBSTR('Boston', 4) AS ending;
Les résultats sont 'Bos' et 'ton'. Le premier appel prend trois caractères à partir de la position 1. Le second omet le nombre de caractères et prend tout à partir de la position 4. PostgreSQL écrit aussi SUBSTRING('Boston' FROM 4 FOR 3). SQLite accepte le nom SUBSTRING à partir de la version 3.34. SQL Server utilise SUBSTRING(text, start, count) ; le nombre de caractères est obligatoire jusqu’à la version 2022 et facultatif à partir de 2025.
SQLite peut compter depuis la droite : SUBSTR('Boston', -3) donne 'ton'. Dans PostgreSQL, une position de départ négative ne compte pas à rebours depuis la fin. Utilise RIGHT('Boston', 3) ; LEFT prend les caractères depuis le début. SQLite n’a ni LEFT ni RIGHT.
Trouver le point de séparation
INSTR(text, search) dans SQLite renvoie la position de la première correspondance. PostgreSQL utilise STRPOS ou POSITION(search IN text). Ces fonctions renvoient 0 si aucune correspondance n’est trouvée. La recherche distingue les majuscules des minuscules : INSTR('Ana', 'a') vaut 3.
Dans 'ana@example.com', le @ est à la position 4. Le nom d’utilisateur se termine juste avant ; le domaine commence juste après :
SUBSTR(email, 1, INSTR(email, '@') - 1) AS user_name,
SUBSTR(email, INSTR(email, '@') + 1) AS domain
La première expression devient SUBSTR(email, 1, 3) et produit 'ana'. La seconde commence à 5 et produit 'example.com'. Omettre - 1 inclut @ dans le nom d’utilisateur. Omettre + 1 l’inclut au début du domaine. Dans PostgreSQL, remplace INSTR par STRPOS ou utilise SPLIT_PART(email, '@', 2) pour le domaine.
Gérer un séparateur manquant
Pour 'anaexample.com', INSTR renvoie 0. La formule du domaine commence à 1 et renvoie toute la chaîne, ce qui est trompeur. La formule du nom d’utilisateur dans SQLite donne une chaîne vide ; PostgreSQL refuse la longueur négative de la sous-chaîne. Protège l’extraction :
CASE
WHEN INSTR(email, '@') > 0
THEN SUBSTR(email, INSTR(email, '@') + 1)
END
Cette expression renvoie NULL lorsque le séparateur est absent. La vérification porte sur la présence d’un séparateur, pas sur toutes les règles de validité d’une adresse e-mail.
Construire des libellés courts et des codes de largeur fixe
SUBSTR(first_name, 1, 1) || '. ' || last_name donne 'A. Lopez' pour Ana Lopez. WHERE LENGTH(zip_code) <> 5 trouve les chaînes enregistrées comme codes postaux américains dont la longueur est incorrecte ; les longueurs NULL produisent UNKNOWN et sont exclues.
LPAD('42', 5, '0') dans PostgreSQL donne '00042' ; RPAD ajoute des caractères à droite. SQLite peut construire ce code avec SUBSTR('00000' || 42, -5). Ne garder que cinq caractères tronque aussi une valeur plus longue : cette expression à largeur fixe exige donc un code qui y tient.
Points clés
- Les positions dans les chaînes SQL commencent à 1 ; LENGTH compte les espaces.
- SUBSTR prend une position de départ et un nombre facultatif de caractères.
- INSTR, STRPOS et POSITION renvoient 0 en l’absence de correspondance.
- Utilise la position moins 1 avant un séparateur et la position plus 1 après.
- Vérifie si le séparateur est absent avant d’extraire une partie.
- L’extraction depuis la fin et le remplissage portent des noms différents dans SQLite et PostgreSQL.
4Manipuler des dates et des heures
Le travail sur les dates commence par une distinction claire entre un jour du calendrier, une heure et un horodatage. SQL peut ensuite créer des libellés de mois, calculer des échéances, mesurer le temps écoulé et filtrer une période complète. Tu distingueras les valeurs de date du texte d’affichage, tiendras compte des fins de mois et des anniversaires et compareras les expressions SQLite et PostgreSQL qui accomplissent une même tâche. Les cas limites rendent ces calculs fiables.
4.1 Écrire, stocker et lire des valeurs de date et d’heure
Il est plus facile de calculer avec une date lorsque son stockage et son écriture sont clairs. Le texte '03/04/2026' pourrait signifier le 4 mars ou le 3 avril. Une date ISO, '2026-03-14', place l’année, le mois et le jour dans un ordre sans ambiguïté.
Associer la valeur à son type
PostgreSQL possède DATE pour un jour du calendrier, TIME pour une heure de la journée et TIMESTAMP pour une date et une heure. Son type TIMESTAMP WITH TIME ZONE, aussi appelé timestamptz, stocke un instant en UTC et l’affiche dans le fuseau horaire de la session. Un TIMESTAMP simple n’inclut pas cette information de fuseau.
SQLite stocke les dates et les heures sous forme de texte ISO ou de nombres, sans types dédiés aux dates et aux heures. Les formes numériques comprennent les jours juliens et le temps Unix. Les fonctions de date interprètent ces valeurs et renvoient une date, une heure ou une mesure numérique.
Utilise du texte ISO de largeur fixe comme '2026-03-14', avec les zéros initiaux. Ajoute une heure au format 24 heures : '2026-03-14 09:30:00'. Le littéral typé DATE '2026-03-14' de PostgreSQL crée explicitement une date.
Préserver l’ordre chronologique
Le texte ISO de largeur fixe se compare dans l’ordre des dates, car il commence par la plus grande composante. '2026-03-14' vient avant '2026-11-02'. Le texte au format d’affichage américain n’a pas cette propriété : en tant que chaînes, '11/02/2025' est trié après '03/14/2026', même si sa date est antérieure.
L’analyseur de SQLite exige un format pris en charge. date('2026-3-14') renvoie NULL parce que le mois ne comporte pas deux chiffres. Il peut aussi normaliser une date impossible : date('2026-02-30') renvoie '2026-03-02'. Un résultat qui n’est pas NULL ne prouve pas à lui seul que l’entrée était un jour valide du calendrier. PostgreSQL rejette DATE '2026-02-30'.
Lire du texte dans un autre format
PostgreSQL et Oracle utilisent TO_DATE('03/14/2026', 'MM/DD/YYYY') pour lire un format américain. PostgreSQL lit aussi le texte ISO avec CAST('2026-03-14' AS DATE) ou '2026-03-14'::date.
SQLite n’a pas d’analyseur TO_DATE. Pour du texte de format fixe MM/DD/YYYY dans d, reconstruis le texte ISO :
SUBSTR(d, 7, 4) || '-' ||
SUBSTR(d, 1, 2) || '-' || SUBSTR(d, 4, 2)
Les parties sont l’année '2026', le mois '03' et le jour '14'. Le résultat est '2026-03-14', que les fonctions de date de SQLite peuvent lire. Ces positions supposent que l’entrée utilise effectivement le format fixe.
Obtenir la date et l’heure actuelles
CURRENT_DATE et CURRENT_TIMESTAMP fonctionnent dans SQLite et PostgreSQL. SQLite renvoie du texte en UTC ; date('now', 'localtime') donne la date locale. Près de minuit, la date UTC et la date locale peuvent différer.
PostgreSQL utilise le fuseau horaire de la session. CURRENT_TIMESTAMP et NOW() correspondent au début de la transaction en cours : attendre dans cette transaction ne fait donc pas avancer leur valeur. MySQL propose NOW() et CURDATE() ; SQL Server possède GETDATE() et SYSDATETIME() ; Oracle possède SYSDATE, qui comprend une heure, et CURRENT_DATE.
Pour vérifier le calcul d’une échéance, utilise d’abord une date de référence fixe comme DATE '2026-10-21' dans PostgreSQL ou '2026-10-21' dans SQLite. Tu peux alors comparer le résultat à un calendrier sans que la réponse change le lendemain.
Points clés
- DATE représente un jour du calendrier ; TIMESTAMP y ajoute une heure.
- Utilise AAAA-MM-JJ de largeur fixe pour écrire des dates portables et sans ambiguïté.
- Le texte ISO se trie chronologiquement lorsque son format et sa référence temporelle sont cohérents.
- SQLite peut normaliser une date impossible au lieu de la rejeter.
- Les fonctions de date actuelle suivent des règles différentes pour les fuseaux horaires et les transactions.
4.2 Extraire et mettre en forme des parties de dates
Extrais une composante de date lorsque tu as besoin d’une année ou d’un jour de la semaine pour calculer. Mets une date en forme lorsque tu as besoin de texte pour un lecteur. Ces opérations peuvent produire des types différents, même si les caractères affichés se ressemblent.
Extraire une année, un mois ou un jour de la semaine
PostgreSQL utilise la forme standard EXTRACT(part FROM value). Pour DATE '2026-03-14', l’extraction de YEAR donne 2026 et celle de MONTH donne 3, tous deux sous forme de nombres. MySQL et Oracle prennent aussi en charge EXTRACT.
SQLite utilise strftime(format, value), qui renvoie du texte :
| Modèle SQLite | Résultat pour '2026-03-14' |
|---|---|
'%Y' | '2026' |
'%m' | '03' |
'%d' | '14' |
'%w' | '6' |
Le %w de SQLite et le DOW de PostgreSQL numérotent les jours de 0 pour le dimanche à 6 pour le samedi. Le 14 mars 2026 est un samedi. ISODOW dans PostgreSQL les numérote de 1 pour le lundi à 7 pour le dimanche. Un filtre de week-end dans SQLite est WHERE strftime('%w', order_date) IN ('0', '6').
Comparer les bons types
strftime('%m', order_date) = 3 est faux pour une date de mars dans SQLite : la fonction renvoie le texte '03', et non le nombre 3. Compare-le avec = '03' ou convertis-le d’abord :
CAST(strftime('%m', order_date) AS INTEGER) = 3
C’est aussi utile dans l’expression du trimestre (CAST(strftime('%m', d) AS INTEGER) + 2) / 3. La division entière donne le trimestre 1 pour mars et le trimestre 4 pour novembre. PostgreSQL possède directement EXTRACT(QUARTER FROM d).
Identifier un mois comme une période entière
strftime('%Y-%m', order_date) crée un libellé SQLite comme '2026-03'. date(order_date, 'start of month') crée '2026-03-01'. PostgreSQL peut utiliser TO_CHAR(order_date, 'YYYY-MM') pour un libellé ou DATE_TRUNC('month', order_date) pour le premier instant de ce mois.
Conserve l’année dans un libellé de période. La seule valeur de mois 3 réunirait les mois de mars de différentes années. La valeur correspondant au premier jour du mois peut rester la valeur utilisée pour les calculs et le tri, tandis qu’une expression distincte fournit l’affichage.
Mettre en forme à l’étape de sortie
Dans PostgreSQL, TO_CHAR(DATE '2026-03-14', 'MM/DD/YYYY') donne '03/14/2026', et le modèle 'Mon DD, YYYY' donne 'Mar 14, 2026'. Oracle utilise aussi ces modèles. Le format américain dans SQLite est strftime('%m/%d/%Y', '2026-03-14').
Les lettres des modèles propres à chaque base de données ont leur signification. Dans PostgreSQL, MM signifie mois et MI minute. Dans SQLite, %m signifie mois et %M minute ; changer cette majuscule change l’information demandée.
SELECT TO_CHAR(order_date, 'MM/DD/YYYY') AS order_day
FROM orders
ORDER BY order_date;
Ici, PostgreSQL affiche du texte lisible mais trie les dates réelles. Trier order_day trierait les chaînes d’affichage d’abord par mois et pourrait placer dans le désordre des dates d’années différentes.
Points clés
- EXTRACT dans PostgreSQL renvoie des composantes numériques ; strftime dans SQLite renvoie du texte.
- Compare un mois SQLite précédé d’un zéro à du texte ou convertis-le en nombre.
- La numérotation des jours de la semaine dépend de la convention demandée.
- Conserve l’année dans les libellés de mois et ne mets en forme que pour l’affichage.
4.3 Calculer avec des dates et filtrer des plages de dates
Les calculs calendaires doivent tenir compte de la longueur des mois, des composantes horaires et du type de réponse recherché. Un nombre de jours, un mois calendaire et une année d’âge révolue sont des mesures différentes.
Ajouter des jours et des mois calendaires
PostgreSQL écrit DATE '2026-03-14' + 30 ; SQLite écrit date('2026-03-14', '+30 days'). Les deux atteignent le 13 avril : 17 jours terminent le mois de mars et 13 jours supplémentaires mènent au 13 avril. L’expression directe '2026-03-14' + 30 dans SQLite donne quant à elle 2056, car l’opération arithmétique lit l’année initiale comme un nombre.
Les fins de mois exigent une règle explicite. DATE '2026-01-31' + INTERVAL '1 month' dans PostgreSQL donne le 28 février à minuit, en utilisant le dernier jour disponible. date('2026-01-31', '+1 month') dans SQLite reporte les jours excédentaires sur mars et donne '2026-03-03'. À partir de SQLite 3.46, ajoute 'floor' après le décalage pour choisir '2026-02-28'. ADD_MONTHS dans Oracle passe aussi au dernier jour du mois plus court.
Mesurer le temps écoulé
Dans PostgreSQL, la soustraction de DATE renvoie des jours entiers : DATE '2026-04-13' - DATE '2026-03-14' vaut 30. SQLite soustrait des valeurs numériques de jours : julianday('2026-04-13') - julianday('2026-03-14') vaut 30.0. SQL Server utilise DATEDIFF(day, start, end) ; MySQL utilise DATEDIFF(end, start).
Pour des horodatages allant du 14 mars à 09 h 30 à 18 h 00, la soustraction dans PostgreSQL donne un intervalle de 08:30:00 ; EXTRACT(EPOCH FROM interval) / 3600 l’exprime sous la forme de 8,5 heures. À partir de SQLite 3.38, on peut écrire :
(unixepoch('2026-03-14 18:00') -
unixepoch('2026-03-14 09:30')) / 3600.0
Cela donne 8.5. Une différence de jours juliens multipliée par 24 peut donner 8.49999999627471 à cause de l’approximation à virgule flottante ; arrondis pour l’affichage. Une durée fractionnaire entre horodatages ne doit pas être convertie en INTEGER avant que l’unité souhaitée ait été calculée.
Compter les anniversaires passés
Une personne née le 2 novembre 1990 a 35 ans le 21 octobre 2026. Les années diffèrent de 36, mais l’anniversaire n’est pas encore arrivé. PostgreSQL utilise EXTRACT(YEAR FROM AGE(DATE '2026-10-21', DATE '1990-11-02')), ce qui donne 35.
SQLite soustrait un si l’anniversaire de cette année n’est pas encore arrivé :
strftime('%Y', '2026-10-21') - strftime('%Y', birth_date)
- (strftime('%m-%d', '2026-10-21') < strftime('%m-%d', birth_date))
La comparaison donne 1 si l’anniversaire est encore à venir et 0 sinon. Diviser les jours écoulés par 365 n’est pas fiable : le 1er novembre 2026, cette personne a vécu 13 148 jours, ce qui, divisé par 365, donne 36,02 alors que son 36e anniversaire est demain. DATEDIFF dans SQL Server compte les frontières : passer du 31 décembre au 1er janvier compte comme une frontière d’année, et non comme une année d’âge révolue.
Inclure tous les horodatages d’une période
BETWEEN inclut les deux bornes. Pour les colonnes DATE, du 1er mars au 31 mars couvre le mois de mars. Pour les horodatages, une borne supérieure de '2026-03-31' signifie minuit au début du dernier jour et manque le reste de cette journée.
WHERE ordered_at >= '2026-03-01'
AND ordered_at < '2026-04-01'
Cette plage semi-ouverte inclut le début et exclut le début de la période suivante, couvrant ainsi toutes les heures de mars sans choisir une dernière fraction de seconde.
Les dates échues satisfont due_date < CURRENT_DATE. La borne inférieure des 30 derniers jours est CURRENT_DATE - 30 dans PostgreSQL et date('now', '-30 days') dans SQLite. Le nombre de jours jusqu’à une échéance est donné par due_date - CURRENT_DATE pour les valeurs DATE dans PostgreSQL et par julianday(due_date) - julianday(date('now')) dans SQLite.
Points clés
- Utilise des fonctions de calcul sur les dates ou des dates typées, plutôt que des opérations arithmétiques sur du texte de date dans SQLite.
- Décide comment l’ajout d’un mois doit traiter un jour absent du mois suivant.
- Les différences entre DATE comptent des jours ; celles entre horodatages peuvent inclure des fractions.
- L’âge compte les anniversaires passés, pas les jours écoulés divisés par 365.
- Une plage d’horodatages semi-ouverte inclut le début de la période et exclut le début de la suivante.
- Utilise une valeur actuelle limitée à la date pour calculer les échéances en jours entiers.
5Classer des lignes avec des expressions CASE
Un rapport a souvent besoin d’une règle qui transforme des données en libellé ou en frais : une petite commande, une expédition en attente ou un rang de priorité. CASE exprime ce choix dans une requête. Tu suivras la condition retenue, placeras les valeurs exactement aux bornes et les valeurs manquantes dans la bonne catégorie, et traduiras des codes avec le CASE simple. Le rapport final combine le classement avec des opérations arithmétiques, du texte, des dates et des valeurs de repli, en vérifiant chaque résultat sur des lignes connues.
5.1 Répartir des lignes en catégories avec un CASE recherché
Une expression CASE choisit un résultat pour chaque ligne. Tu peux l’utiliser pour attribuer un libellé à une tranche de prix, calculer des frais ou marquer un enregistrement qui mérite une attention particulière.
Lire la forme recherchée
CASE
WHEN total < 50 THEN 'small'
WHEN total < 200 THEN 'medium'
ELSE 'large'
END AS size_band
Chaque WHEN fournit une condition et THEN fournit la valeur à renvoyer si cette condition vaut TRUE. La base de données vérifie les conditions de haut en bas et retient la première condition vraie. END ferme l’expression ; un alias peut le suivre. Si aucune condition ne vaut TRUE et que ELSE est absent, le résultat est NULL.
Un total de 35 remplit la première condition et devient 'small'. Un total de 50 ne remplit pas la première mais remplit la deuxième et devient 'medium'. Il en va de même pour 199,99. Un total de 200 atteint ELSE et devient 'large'.
Faire correspondre l’ordre et les bornes à la règle
La deuxième branche n’a pas besoin de total >= 50 : une valeur inférieure à 50 a déjà donné lieu à un résultat dans la première branche. Les seuils croissants avec < fonctionnent parce que les branches précédentes ont déjà traité les valeurs plus petites. Des seuils décroissants avec >= peuvent fonctionner pour la même raison.
Placer WHEN total < 200 en premier rend inaccessible une branche < 50 ultérieure. Un total de 35 satisfait déjà < 200, donc il s’arrête là. CASE ne choisit pas la condition la plus précise et ne vérifie pas quel libellé semble le mieux convenir.
Compare la règle métier à chaque borne. < 50 place exactement 50 dans la tranche moyenne ; <= 50 le place dans la petite tranche. Vérifie 49,99, 50, 199,99 et 200 pour examiner les deux côtés et les bornes. Si les conditions sont écrites sous forme d’intervalles explicites, fais correspondre leurs bornes sans laisser de vide ni de chevauchement involontaire.
Traiter NULL avant les plages ordinaires
Un total NULL rend les deux comparaisons UNKNOWN. Dans la première expression, il atteint donc ELSE et devient 'large', ce qui est trompeur. Détecte d’abord les valeurs manquantes :
CASE
WHEN total IS NULL THEN 'unknown'
WHEN total < 50 THEN 'small'
WHEN total < 200 THEN 'medium'
ELSE 'large'
END
ELSE signifie « aucune condition n’était vraie » : il peut donc prendre en compte les entrées manquantes aussi bien que les valeurs connues situées hors des plages testées.
Renvoyer un type de valeur cohérent
PostgreSQL exige des types compatibles pour THEN et ELSE. CASE WHEN quantity > 0 THEN unit_price ELSE 'n/a' END échoue si unit_price est numérique, car 'n/a' ne peut pas devenir un nombre. Utilise NULL pour un résultat numérique indisponible, ou convertis le prix en texte si toute la sortie est un libellé d’affichage. SQLite autorise des types de résultats mélangés, ce qui peut compliquer les calculs ultérieurs.
Une condition peut combiner des colonnes :
CASE
WHEN country = 'US' AND subtotal >= 100 THEN 0
ELSE 7.99
END AS shipping_fee
Les frais renvoyés peuvent figurer dans subtotal + CASE ... END AS amount_due. Un CASE est une expression qui produit une valeur, pas une commande qui modifie plusieurs colonnes ; chaque colonne de résultat a besoin de sa propre expression.
CASE peut aussi protéger une division effectuée sur chaque ligne : CASE WHEN visits = 0 THEN NULL ELSE orders * 100.0 / visits END. Une ligne dont la valeur est nulle sélectionne la branche NULL. orders * 100.0 / NULLIF(visits, 0) exprime la même règle de taux manquant plus brièvement.
Points clés
- CASE renvoie la valeur associée à la première condition qui vaut TRUE.
- Ordonne les conditions de plages qui se chevauchent pour qu’un test large ne masque pas un test plus restreint.
- Choisis < ou <= pour placer une valeur exactement à la borne dans la tranche voulue.
- Teste explicitement NULL avant une plage lorsque ELSE ne doit pas lui attribuer de libellé.
- Garde des types de résultats compatibles et utilise CASE partout où une expression de valeur convient.
5.2 Utiliser le CASE simple et employer CASE dans toute une requête
La forme CASE simple traduit une valeur en une autre. Le CASE recherché teste des conditions ; le CASE simple compare la même expression à une série de valeurs.
Traduire des codes avec le CASE simple
CASE status
WHEN 'S' THEN 'Shipped'
WHEN 'P' THEN 'Pending'
WHEN 'C' THEN 'Canceled'
ELSE 'Other'
END AS status_label
Les tests implicites sont status = 'S', puis status = 'P', puis status = 'C'. Un statut hors de ces codes reçoit 'Other'. La forme recherchée peut écrire explicitement les mêmes tests d’égalité. Choisis le CASE recherché pour les plages, les motifs LIKE, les tests NULL ou les conditions portant sur plusieurs colonnes.
CASE region WHEN NULL THEN 'missing' ELSE region END ne peut pas détecter une région NULL. Son test implicite region = NULL vaut UNKNOWN, donc la ligne atteint ELSE et reste NULL. Écris CASE WHEN region IS NULL THEN 'missing' ELSE region END.
Attribuer un rang de tri personnalisé
L’ordre alphabétique des priorités est high, low, medium. Pour trier selon l’urgence, traduis les libellés en nombres :
SELECT ticket_id, priority
FROM tickets
ORDER BY CASE priority
WHEN 'high' THEN 1
WHEN 'medium' THEN 2
WHEN 'low' THEN 3
ELSE 4
END;
L’ordre croissant place maintenant high avant medium, puis low, avec les autres valeurs ou les valeurs manquantes en dernier. Le CASE est une expression de tri ; il n’a pas besoin d’être une colonne affichée. Utiliser DESC inverserait le classement numérique.
Créer un indicateur numérique
CASE WHEN discount_pct > 0 THEN 1 ELSE 0 END AS is_discounted
Un pourcentage positif reçoit 1 ; un zéro connu reçoit 0. Un pourcentage NULL reçoit aussi 0 parce que > 0 vaut UNKNOWN et que ELSE le prend en compte. Cet indicateur signifie donc « une remise positive est enregistrée ». Il ne conserve pas la distinction entre l’absence de remise et une remise inconnue. Si cette distinction est nécessaire, ajoute une branche IS NULL avec son propre résultat.
Les indicateurs peuvent être sélectionnés, triés, filtrés ou inclus dans des opérations arithmétiques. Dans une clause WHERE portable, répète l’expression ou utilise sa condition d’origine au lieu de faire référence à un alias de sortie nouvellement défini.
Reconnaître les fonctions conditionnelles associées
COALESCE(bonus, 0) est une forme abrégée de CASE WHEN bonus IS NOT NULL THEN bonus ELSE 0 END. NULLIF(a, b) correspond à CASE WHEN a = b THEN NULL ELSE a END. Leurs noms communiquent directement ces usages courants.
SQLite à partir de la version 3.32 et SQL Server possèdent IIF(condition, true_value, false_value) ; MySQL possède IF. DECODE dans Oracle traduit les correspondances par égalité, par exemple DECODE(status, 'S', 'Shipped', 'P', 'Pending', 'Other'). DECODE considère deux NULL comme égaux, contrairement aux comparaisons d’égalité du CASE simple. Le CASE standard fonctionne dans ces systèmes.
Un CASE peut contenir un autre CASE, mais des conditions combinées rendent souvent une expression sans imbrication plus claire. Une règle d’expédition peut dire directement WHEN country = 'US' AND subtotal >= 100 THEN 0, en gardant ensemble les tests sur le pays et le sous-total.
Points clés
- Le CASE simple compare une expression à des valeurs par égalité.
- Utilise le CASE recherché pour les tests NULL, les plages et les conditions combinées.
- Un CASE numérique dans ORDER BY crée un classement personnalisé.
- Un indicateur avec ELSE 0 attribue aussi zéro lorsque sa condition vaut UNKNOWN.
- COALESCE et NULLIF expriment des cas particuliers courants de CASE.
- DECODE dans Oracle considère deux NULL comme égaux ; le CASE simple ne le fait pas.
5.3 Combiner des fonctions dans une requête de rapport complète
Un rapport peut nettoyer des noms, calculer des totaux nets, identifier des mois et attribuer un libellé à la rapidité d’expédition dans un seul SELECT. Construis chaque expression à partir de ses entrées et vérifie le résultat avant de la combiner aux autres.
Partir de lignes connues
Une table de commandes contient ces enregistrements. Les dates sont du texte ISO pour la requête SQLite ci-dessous ; quantity est un entier et unit_price est numérique.
| Commande | Client | Quantité | Prix | Remise % | Commandée | Expédiée |
|---|---|---|---|---|---|---|
| 1001 | Ana Lopez | 3 | 12,50 | 10 | 2026-03-14 | 2026-03-17 |
| 1002 | Ben Okafor | 1 | 240,00 | 0 | 2026-03-30 | NULL |
| 1003 | Chen Wu | 12 | 4,25 | NULL | 2026-04-02 | 2026-04-03 |
Ici, une remise manquante signifie qu’il n’y a pas de remise. Commence par extraire les champs bruts. Ajoute une colonne calculée à la fois et utilise LIMIT 5 pour vérifier un petit échantillon.
Suivre un calcul imbriqué
ROUND(quantity * unit_price *
(1 - COALESCE(discount_pct, 0) / 100.0), 2)
COALESCE fournit d’abord une remise connue. La division par 100.0 conserve sa partie fractionnaire. La soustraction à 1 donne la fraction payée, la multiplication donne le montant net et ROUND fixe la précision finale. Le montant d’Ana est 33.75, celui de Ben est 240.0 et celui de Chen est 51.0. La remise NULL de Chen devient zéro ; une date d’expédition manquante, en revanche, doit rester manquante dans le nombre de jours.
Assembler le rapport SQLite
SELECT order_id,
first_name || ' ' || last_name AS customer,
ROUND(quantity * unit_price *
(1 - COALESCE(discount_pct, 0) / 100.0), 2) AS net_total,
strftime('%Y-%m', order_date) AS order_month,
CAST(julianday(shipped_date) - julianday(order_date)
AS INTEGER) AS days_to_ship,
CASE
WHEN shipped_date IS NULL THEN 'not shipped'
-- fast = shipped within 2 days
WHEN julianday(shipped_date) - julianday(order_date) <= 2
THEN 'fast'
ELSE 'standard'
END AS shipping
FROM orders
ORDER BY order_id;
Chaque expression possède un alias de sortie explicite. La différence numérique en jours est convertie en INTEGER car ces valeurs ne contiennent que des dates. La branche IS NULL vient avant la comparaison de rapidité, de sorte qu’une commande non expédiée reçoit un libellé utile.
Le résultat est :
| Commande | Client | Total net | Mois | Jours | Expédition |
|---|---|---|---|---|---|
| 1001 | Ana Lopez | 33.75 | 2026-03 | 3 | standard |
| 1002 | Ben Okafor | 240.0 | 2026-03 | NULL | not shipped |
| 1003 | Chen Wu | 51.0 | 2026-04 | 1 | fast |
Adapter les types et les clauses de la requête
Pour des colonnes DATE dans PostgreSQL, utilise TO_CHAR(order_date, 'YYYY-MM') pour le mois et shipped_date - order_date pour le nombre de jours et la comparaison dans CASE. Garde unit_price dans le type exact numeric pour ROUND à deux arguments. La concaténation, la valeur de repli pour la remise et la règle de classement gardent le même sens.
Pour filtrer les totaux arrondis supérieurs à 50 dans les deux bases, répète l’expression complète du montant net dans WHERE. Les commandes 1002 et 1003 restent. SQLite autorise aussi WHERE net_total > 50, mais PostgreSQL ne peut pas voir ce nouvel alias à l’étape du filtrage. ORDER BY net_total DESC fonctionne dans les deux.
Lorsque tu transfères un rapport, vérifie les types et les noms de fonctions dans chaque expression. Une fonction de texte doit recevoir du texte, un calcul de date doit recevoir une valeur de date prise en charge et une valeur de repli numérique doit exprimer la règle voulue. Place chaque résultat sur sa propre ligne ; un court commentaire peut définir un seuil métier sans rendre le SQL difficile à lire.
Points clés
- Construis et vérifie une colonne calculée à la fois sur un petit échantillon.
- Les fonctions imbriquées transmettent leurs résultats vers l’extérieur ; veille à ce que chaque entrée ait le type adapté.
- Une remise manquante et une date d’expédition manquante peuvent nécessiter des traitements différents.
- Utilise des expressions de date adaptées au dialecte tout en gardant des règles de rapport cohérentes.
- Filtre avec l’expression complète et trie avec son alias de sortie lorsque c’est approprié.
Colonnes calculées SQL : exemples
1Calculer et vérifier le montant d’une ligne après remise
16 étapes
- 1IntroductionTransformer une ligne en montant utile
Une ligne de commande enregistre huit articles à 7,50 chacun avec une remise de 20 pour cent. Le rapport a besoin d’un montant net, mais la table ne stocke que les données de départ. Tu construiras l’expression par étapes, nommeras sa sortie et vérifieras l’effet de la division entière sur la remise.
Les exemples utilisent SQLite et PostgreSQL. Lorsque leurs règles de type diffèrent, le nom de la base de données précise à quel résultat il correspond.
- 2ExplicationCommencer par une expression
Une expression combine des valeurs pour produire une autre valeur. Ici,
quantity * unit_priceutilise deux colonnes de la ligne courante.SELECT quantity * unit_price AS gross_total FROM order_lines;gross_totalest l’alias de sortie. Pour la ligne de l’exemple, la nouvelle valeur est60.0dans SQLite. Chaque autre ligne fournit ses propres données ; la requête ne réécrit pas ces totaux dans la table. - 3LienChaque ligne conserve sa propre valeur
Une fonction monoligne renvoie une valeur pour chaque ligne d’entrée.
ROUND(unit_price, 0)modifie le prix affiché pour une ligne, tandis queUPPER(item_name)modifie le texte affiché.Ces fonctions ne combinent pas les lignes de commande. Un agrégat comme SUM combine les valeurs d’un groupe et répond donc à un autre type de question. Un calcul dans SELECT peut conserver le détail des commandes individuelles.
- 4ConseilNommer clairement le résultat
AS net_totalest un alias simple et lisible. Utilise des guillemets doubles lorsqu’un nom contient un espace, comme dansAS "Net Total". Les apostrophes désignent quant à elles les valeurs textuelles.Garde une virgule entre les expressions de sortie.
SELECT quantity unit_pricerenvoie une colonne de quantités sous l’en-tête unit_price : sans virgule, le deuxième nom devient un alias. Cette requête peut réussir tout en affichant moins de colonnes que prévu. - 5DéfiPlacer l’alias dans la requête
La table ne contient que quantity et unit_price. Une requête définit
quantity * unit_price AS gross_total. Un filtre WHERE dans PostgreSQL peut-il utilisergross_total > 50, et ORDER BY peut-il utilisergross_total DESC?---reveal---
WHERE ne peut pas voir ce nouvel alias parce qu’il précède logiquement SELECT. Répète
quantity * unit_price > 50. ORDER BY suit SELECT et peut utilisergross_total DESC. SQLite autorise l’alias dans WHERE comme extension, mais pas PostgreSQL. - 6ExempleTransformer une remise en fraction payée
Le montant brut est
8 * 7.50, soit 60. Une remise de 20 pour cent laisse 80 pour cent à payer. Exprime cela par1 - discount_pct / 100.0.quantity * unit_price * (1 - discount_pct / 100.0)La division donne
0.2; les parenthèses donnent0.8; la multiplication donne un montant net de48.0. Les parenthèses maintiennent la soustraction comme un seul facteur multiplicatif. - 7Point cléUn décimal ultérieur ne peut pas corriger une division antérieure
Supposons que discount_pct soit un entier et que le diviseur soit écrit
100. SQLite et PostgreSQL calculent20 / 100comme une division entière et obtiennent 0. Le facteur devient 1, donc le montant net reste à tort égal à 60.Le prix décimal ailleurs dans l’expression ne corrige pas cette division intérieure. Utilise
100.0dans la division elle-même. Convertir le quotient une fois calculé change son type mais ne peut pas restaurer la fraction perdue. - 8DéfiTrouver le calcul qui a perdu sa fraction
Une ligne SQLite contient les entiers completed = 9 et assigned = 12. Que renvoie
completed / assigned * 100.0, et comment l’expression devrait-elle calculer le pourcentage ?---reveal---
Elle renvoie
0.0: la division entière9 / 12devient d’abord 0. Écriscompleted * 100.0 / assigned, ce qui donne75.0. La conversion doit avoir lieu avant la division, et pas seulement avant l’affichage final. - 9ExplicationChoisir la règle pour obtenir un entier
ROUND choisit une valeur arrondie proche. FLOOR descend jusqu’à un entier, CEIL monte et TRUNC supprime la partie fractionnaire par troncation vers zéro.
Pour
-6.4, FLOOR donne-7, tandis que CEIL et TRUNC donnent-6. Le sens compte pour les entrées négatives. PostgreSQL fournit ces fonctions ; dans SQLite, CEIL, FLOOR et TRUNC exigent une version compilée avec les fonctions mathématiques. ABS, qui donne la distance à zéro, est intégré à SQLite. - 10ConseilVérifier le type numérique avant d’arrondir
Dans PostgreSQL, ROUND à deux arguments prend
numeric, pas double precision. Pour une colonne à virgule flottante, écrisROUND(CAST(amount AS numeric), 2). SQLite accepte sa propre forme numérique de ROUND.Les valeurs approximatives à virgule flottante peuvent produire des cas d’arrondi à mi-chemin surprenants. Pour les montants exacts, NUMERIC/DECIMAL dans PostgreSQL stocke des décimaux exacts ; SQLite peut conserver des centimes entiers comme entiers. Arrondis le résultat affiché après le calcul.
- 11ExplicationRendre explicite un changement de type
CAST(expression AS type)demande une conversion. Le texte'28'peut devenir l’entier 28 avecCAST('28' AS INTEGER). Le nombre peut devenir du texte avecCAST(28 AS TEXT).Pour une division avec résultat fractionnaire, SQLite exige REAL afin d’obtenir un opérande non entier de façon fiable.
CAST(7 AS NUMERIC)peut encore y être l’entier 7. NUMERIC dans PostgreSQL fournit un type décimal exact. Une conversion CAST de NULL reste NULL. - 12ExempleDistinguer les identifiants des quantités
Supposons qu’un libellé stocke le code postal américain
'00421'. Le convertir en entier donne421, ce qui fait perdre les zéros initiaux. C’est un identifiant : il ne s’agit donc pas de faire des calculs avec lui.Une colonne de texte qui contient réellement des quantités peut nécessiter une conversion pour un tri numérique. Les textes
'12','3'et'80'sont triés dans cet ordre ; le tri numérique donne 3, 12, 80. Choisis la conversion selon le sens de la colonne. - 13DéfiInterpréter une conversion sans la prendre pour une validation
SQLite exécute
CAST('31units' AS INTEGER)sans erreur. Quelle valeur renvoie-t-il, et cette réussite montre-t-elle que le texte d’origine était un entier valide ?---reveal---
Il renvoie 31 en lisant la partie numérique initiale. La réussite ne valide pas toute la chaîne. PostgreSQL rejette le même texte comme entier. SQLite peut aussi transformer en zéro un texte sans préfixe numérique, masquant ainsi une entrée incorrecte.
- 14Point cléUne conversion en entier ne fonctionne pas partout de la même façon
Pour la valeur numérique
4.7,CAST(... AS INTEGER)dans SQLite tronque à 4, tandis que PostgreSQL arrondit à 5. Si un rapport demande « les unités entières ne dépassant pas cette valeur », exprime cette règle avec FLOOR avant la conversion.Une conversion implicite dépend aussi de la base de données. PostgreSQL peut déduire un nombre à partir d’un littéral entre apostrophes dans une opération arithmétique, mais une colonne TEXT exige une conversion explicite. Les seuls caractères visibles ne déterminent pas le type de l’opérande.
- 15DéfiVérifier l’expression complète du montant net
Pour huit articles à 7,50 avec l’entier discount_pct = 20, un rapport utilise
ROUND(quantity * unit_price * (1 - discount_pct / 100.0), 2) AS net_total. Quel est le résultat, et cet alias peut-il servir à trier la sortie ?---reveal---
Le montant brut est 60, la fraction payée est 0,8 et le montant net est
48.0dans SQLite.ORDER BY net_totalest valide dans SQLite et PostgreSQL, car le tri peut voir l’alias SELECT. - 16RécapitulatifLire les données d’entrée, le calcul et le nom de sortie
Un montant calculé suit un parcours : la ligne fournit les valeurs, les opérations arithmétiques et les fonctions produisent le résultat, et un alias le nomme. Vérifie l’ordre des opérations et les types des opérandes avant d’accepter un nombre affiché.
Lorsqu’un résultat est inattendu, examine d’abord une division ou une conversion intérieure. Pour filtrer une valeur calculée dans différentes bases de données, répète son expression dans WHERE ; pour la trier, utilise l’alias de sortie dans ORDER BY.
2Suivre les données manquantes dans une requête
12 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionUn montant manquant affecte plus qu’une cellule
- 2ExplicationNULL est une entrée inconnue
- 3ExempleUtiliser un test qui détecte les valeurs manquantes
- 4Point cléWHERE n’accepte que TRUE
- 5DéfiCombiner une condition connue et une condition inconnue
- 6ConseilNe pas laisser NULL dans une liste d’exclusion
- 7ExplicationChoisir une valeur de repli selon le sens
- 8ExempleGarder un type d’affichage cohérent
- 9ExempleTransformer un dénominateur nul en valeur manquante
- 10DéfiNettoyer la chaîne vide avant d’attribuer le libellé
- 11DéfiDistinguer le choix d’affichage du choix de filtrage
- 12RécapitulatifGarder visible le sens d’une valeur manquante
3Nettoyer un nom et extraire un domaine d’adresse e-mail
14 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionRendre le texte utilisable sans perdre ses parties
- 2ExempleFournir l’espace entre les noms
- 3ExplicationDécider de l’effet d’une partie de nom manquante
- 4ExempleNettoyer l’adresse e-mail de l’intérieur vers l’extérieur
- 5DéfiChoisir entre suppression aux extrémités et remplacement
- 6ConseilVérifier les règles relatives aux caractères et au dialecte
- 7ExplicationCompter à partir de un
- 8ExempleRepérer le séparateur
- 9ExemplePrendre les caractères avant et après @
- 10DéfiTrouver le résultat décalé d’une position
- 11Point cléUn résultat de recherche nul demande un traitement particulier
- 12ConseilExtraire les fins et remplir les codes dans le bon dialecte
- 13DéfiCombiner nettoyage et extraction
- 14RécapitulatifSuivre les caractères exacts
4Créer des libellés de date et des filtres de période fiables
18 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionDistinguer la date calendaire de son libellé
- 2ExplicationChoisir une représentation claire de la date
- 3ExempleLire un format local fixe
- 4DéfiExpliquer quel texte se trie dans l’ordre des dates
- 5ConseilVérifier l’analyse et la référence temporelle actuelle
- 6ExempleExtraire le mois avec le bon type de retour
- 7ExplicationConserver l’année dans le libellé de mois
- 8ExempleCréer un affichage sans modifier le tri
- 9DéfiTrouver le bon trimestre
- 10LienChoisir la convention de numérotation des jours de la semaine
- 11ExempleAjouter dix jours à la réservation
- 12Point cléUn mois n’est pas un nombre fixe de jours
- 13ExempleMesurer les jours et les heures dans les unités adaptées
- 14DéfiInclure le dernier après-midi du mois
- 15ExplicationCompter les anniversaires effectivement passés
- 16ConseilLire les dates relatives comme des bornes mobiles
- 17DéfiCombiner une échéance et une sélection par mois
- 18RécapitulatifVérifier le type, la règle calendaire et les bornes
5Attribuer des libellés aux commandes et construire le rapport final
17 étapes
Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.
- 1IntroductionDonner un libellé utile à chaque commande
- 2ExplicationChoisir la première condition vraie
- 3ExempleSuivre le seuil exact
- 4Point cléELSE peut aussi prendre en compte un montant inconnu
- 5DéfiCorriger une tranche de petits montants masquée
- 6ConseilRenvoyer des résultats compatibles
- 7ExempleTraduire une valeur de statut
- 8DéfiPourquoi WHEN NULL ne détecte-t-il pas la ligne ?
- 9ExempleTrier les priorités par rang
- 10Point cléUn indicateur peut réunir des cas connus et inconnus
- 11ExempleCommencer le rapport avec des données connues
- 12ExempleCalculer d’abord le montant net
- 13ExempleAjouter les dates avec une règle distincte pour les valeurs manquantes
- 14DéfiVérifier une deuxième ligne selon les deux règles
- 15LienTransposer les expressions de date dans PostgreSQL
- 16DéfiFiltrer le montant réellement affiché par le rapport
- 17RécapitulatifVérifier le rapport comme un ensemble de choix explicites
Colonnes calculées SQL : QCM
Série 1 : Calculer des montants et gérer les données manquantes10 Questions Pratiques
Question 1 sur 10
units et unit_cost. Quelle liste SELECT renvoie leur produit sous l’en-tête extended_cost ?Afficher la réponseMasquer la réponse
units * unit_cost multiplie les valeurs de chaque ligne et AS extended_cost nomme cette sortie. Ajouter une virgule avant le nom demande une colonne distincte, que cette table ne possède pas. Les apostrophes feraient de unit_cost un littéral textuel au lieu d’une référence à la colonne de coût.Question 2 sur 10
lines ne contient que units et price. Une requête doit fonctionner dans SQLite et PostgreSQL. Comment doit-elle conserver les lignes dont le produit est supérieur à 90 et trier le produit le plus élevé en premier ?Afficher la réponseMasquer la réponse
units * price dans WHERE, car PostgreSQL ne peut pas utiliser un nouvel alias SELECT à cette étape. ORDER BY vient logiquement après SELECT et peut donc trier selon l’alias avec DESC. SQLite peut accepter l’alias dans WHERE, mais cette version ne satisferait pas l’exigence de fonctionner dans les deux bases.Question 3 sur 10
SELECT 14 + 5 * 3; dans SQLite ?Afficher la réponseMasquer la réponse
5 * 3, soit 15, puis ajoute 14 pour obtenir 29. Le résultat 57 provient de l’addition préalable de 14 et 5. Cet ordre exigerait des parenthèses autour de 14 + 5 ; l’expression présentée n’en comporte pas.Question 4 sur 10
old_count et new_count sont des entiers qui contiennent 60 et 69. Quel est le résultat de (new_count - old_count) / old_count * 100 ?Afficher la réponseMasquer la réponse
9 / 60 est une division entière qui produit 0 avant la multiplication par 100. Le pourcentage recherché est 15, mais l’expression perd d’abord sa partie fractionnaire. Écrire (new_count - old_count) * 100.0 / old_count permet de conserver le calcul décimal nécessaire.Question 5 sur 10
units = 5 et discount_pct = 12, ainsi que price = 18.0. Quel résultat produit ROUND(units * price * (1 - discount_pct / 100), 2) ?Afficher la réponseMasquer la réponse
12 / 100 utilise deux entiers : SQLite la tronque donc à 0. Le facteur devient 1 et ROUND reçoit le montant total, 5 * 18.0, ce qui donne 90.0. Le montant après remise de 79,2 exige un opérande décimal dans cette division ; un arrondi ultérieur ne peut pas restaurer la fraction perdue.Question 6 sur 10
CAST('27boxes' AS INTEGER) ?Afficher la réponseMasquer la réponse
Question 7 sur 10
delivery_date enregistrée ?Afficher la réponseMasquer la réponse
IS NULL teste directement si une valeur est manquante et renvoie une réponse certaine : TRUE ou FALSE. L’égalité avec NULL produit UNKNOWN même pour une date de livraison manquante, donc WHERE ne conserverait aucune de ces lignes. Une chaîne vide est une chaîne enregistrée dans SQLite et PostgreSQL, pas le marqueur d’une date inconnue.Question 8 sur 10
region : 'East', 'West', NULL et 'North'. Combien de lignes satisfont WHERE NOT (region = 'East') ?Afficher la réponseMasquer la réponse
Question 9 sur 10
'unlisted'. Quelle expression permet cela tout en conservant les numéros enregistrés ?Afficher la réponseMasquer la réponse
COALESCE(phone, '', 'unlisted') laisse la chaîne vide intacte et la sélectionne même comme valeur de repli avant d’atteindre le libellé.Question 10 sur 10
sales et visits. Un taux doit conserver les pourcentages fractionnaires et rester NULL lorsque visits vaut zéro. Il ne doit pas inventer un taux nul. Quelle expression convient ?Afficher la réponseMasquer la réponse
Série 2 : Nettoyer du texte et manipuler des valeurs calendaires10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
LOWER(TRIM(' RAE@Mail.COM ')) dans SQLite ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
first_name = 'Mira', middle_name = NULL et last_name = 'Shah'. Que renvoient first_name || ' ' || middle_name || ' ' || last_name et CONCAT_WS(' ', first_name, middle_name, last_name), dans cet ordre ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
SUBSTR('Seattle', 3, 3) ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
email peut contenir NULL ou du texte sans @. Pour un texte contenant @, renvoie tout ce qui suit son premier @ ; sinon, renvoie NULL. Quelle expression convient ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
date('2027-04-31') ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
d contient '2027-08-19'. Quels sont les résultats de strftime('%m', d) = 8 et de CAST(strftime('%m', d) AS INTEGER) = 8, dans cet ordre ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
event_date couvre plusieurs années. Un rapport affiche les dates au format MM/JJ/AAAA et doit conserver l’ordre chronologique. Comment doit-il sélectionner et trier la colonne ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
d vaut '2027-04-24'. Que renvoie date(d, '+10 days') ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Série 3 : Classer des lignes et diagnostiquer la logique d’un rapport10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
score = 75 : CASE WHEN score < 60 THEN 'review' WHEN score < 80 THEN 'ready' ELSE 'strong' END ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
CASE WHEN amount < 500 THEN 'regular' WHEN amount < 100 THEN 'small' ELSE 'large' END ne renvoie-t-il jamais 'small' pour les montants qui ne sont pas NULL ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
balance peut être NULL. Les libellés requis sont 'unknown' si elle est manquante, 'credit' en dessous de 0, 'settled' à 0 et 'due' au-dessus de 0. Quel CASE respecte toutes ces règles ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
state, la valeur 'H' signifie « retenu » et 'R' signifie « libéré ». Que renvoie CASE state WHEN 'H' THEN 'held' WHEN 'R' THEN 'released' ELSE 'other' END pour 'R' ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
'urgent', 'normal' et 'deferred' dans cet ordre, avec toutes les autres priorités et les priorités NULL en dernier. Quelle expression ORDER BY convient ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
qty = 4, price = 15.0, discount_pct = NULL et shipped_date = NULL. Une remise manquante signifie qu’il n’y en a pas. Quel couple est produit par ROUND(qty * price * (1 - COALESCE(discount_pct, 0) / 100.0), 2) et CASE WHEN shipped_date IS NULL THEN 'open' ELSE 'sent' END ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
LOWER(TRIM(customer)) AS name et date(due_date, '+7 days') AS reminder_date. La valeur brute de customer est ' IVAN ' et due_date vaut '2027-09-26'. Quel couple de sortie une vérification par échantillon doit-elle trouver ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
x 2, 7, NULL et 11. Quels sont les nombres de lignes pour WHERE x NOT IN (2, NULL) et WHERE x <> 2 OR x IS NULL, respectivement ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
'1998-12-18'. Au '2027-12-17', quel est son âge révolu et pourquoi la soustraction des deux années peut-elle être erronée ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
rating peut être NULL. Une colonne d’affichage doit montrer la note sous forme de texte ou afficher 'unrated'. Quelle expression convient ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Série 4 : Vérifier des rapports complets et des valeurs limites délicates10 Questions Pratiques
Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.
Question 1 sur 10
qty, la valeur NUMERIC price et l’entier discount_pct. Une remise manquante signifie qu’il n’y en a pas. Un rapport doit conserver les totaux nets arrondis supérieurs à 75 et les trier du plus élevé au plus faible. Quelle requête complète convient ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 2 sur 10
reading est de type DOUBLE PRECISION. Comment un rapport peut-il l’arrondir à deux décimales sans erreur de signature de fonction ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 3 sur 10
COALESCE(NULL, '', 'backup') dans SQLite ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 4 sur 10
email = 'nora@research.org'. Quel résultat produit SUBSTR(email, INSTR(email, '@')) ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 5 sur 10
'2027-01-31', compare date(d, '+1 month') dans SQLite 3.46 ou ultérieur, date(d, '+1 month', 'floor') dans SQLite et DATE '2027-01-31' + INTERVAL '1 month' dans PostgreSQL. Quelles dates calendaires obtient-on, dans cet ordre ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 6 sur 10
stock peut être NULL. L’indicateur numérique requis est NULL pour un stock inconnu, 1 pour un stock inférieur à 5 et 0 sinon. Quelle expression convient ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 7 sur 10
'2027-05-08 10:15:00' à '2027-05-08 13:45:00'. Que renvoie (unixepoch(end_time) - unixepoch(start_time)) / 3600.0 ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 8 sur 10
qty = 6, price = 8.0, discount_pct = 25, a été passée le '2027-07-10' et expédiée le '2027-07-12'. Le montant net utilise ROUND(qty * price * (1 - COALESCE(discount_pct, 0) / 100.0), 2). Un CASE attribue 'open' à une expédition NULL, 'fast' si le nombre de jours écoulés est <= 2, et 'standard' sinon. Quels montant net et libellé obtient-on ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 9 sur 10
d. Comment peut-il calculer le trimestre pour chaque mois ?Afficher la réponseMasquer la réponse
Enregistre cette unité pour voir cette réponse.
Question 10 sur 10
(qty 3, price 22.0, discount_pct NULL), B (qty 4, price 20.0, discount_pct 25) et C (qty 2, price 40.0, discount_pct 10). Une remise manquante signifie qu’il n’y en a pas. Elle calcule ROUND(qty * price * (1 - COALESCE(discount_pct, 0) / 100.0), 2) AS net, conserve net > 60 avec l’expression complète dans WHERE et trie par net DESC. Quel est l’ordre des lignes ?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
A
Affinité de type
Alias de colonne
AS line_total et peut le trier avec ORDER BY line_total.Â
Âge révolu
B
Branche WHEN
< 200 peut empêcher qu’une branche ultérieure < 50 soit sélectionnée.C
CASE recherché
CASE WHEN total < 50 THEN 'small' ELSE 'large' END choisit un libellé à partir du montant de la ligne.CASE simple
CASE status WHEN 'S' THEN 'Shipped' ELSE 'Other' END traduit un code de statut stocké.CEIL
CEIL(4.1) donne 5 car quatre est inférieur à l’entrée et cinq est l’entier suivant.Chaîne de caractères
' New York ' contient des espaces aux extrémités et deux espaces intérieurs qui influent sur sa longueur.Chaîne numérique
'10', '100' et '9' apparaissent dans cet ordre croissant en tant que textes, ce qui diffère de l’ordre numérique.Changement de casse
LOWER(TRIM(email)) rend une adresse e-mail ASCII nettoyée cohérente pour une comparaison après uniformisation de la casse.COALESCE
COALESCE(mobile_phone, home_phone, 'no phone') utilise le numéro fixe si le numéro de portable est manquant.Collation
'Boston' = 'boston' vrai alors que ce n’est pas le cas dans SQLite par défaut.Colonne calculée
quantity * unit_price AS line_total même si la table n’a pas de colonne line_total.Comparaison sûre avec NULL
NULL IS NOT DISTINCT FROM NULL vaut TRUE dans PostgreSQL et dans SQLite à partir de la version 3.39.Concaténation
first_name || ' ' || last_name insère un espace entre les deux parties enregistrées du nom.Conversion explicite
CAST(quantity AS REAL) / 4 change l’opérande SQLite avant que la division ne puisse faire perdre une fraction.Conversion implicite
'Order #' || 42, ce qui produit le libellé 'Order #42'.D
DATE
DATE '2026-03-14' désigne explicitement le 14 mars 2026 comme une valeur de date PostgreSQL.Division entière
7 / 2 produit 3 ; rendre le deuxième opérande 2.0 conserve la fraction et produit 3.5.E
Expression
quantity * unit_price est une expression qui produit le montant de la ligne pour chaque ligne.EXTRACT
EXTRACT(MONTH FROM DATE '2026-03-14') dans PostgreSQL renvoie la valeur numérique de mois 3.F
FLOOR
FLOOR(-4.1) vaut -5 : le résultat diffère donc d’une simple suppression de la partie fractionnaire.Fonction monoligne
UPPER(city) dans SELECT modifie le texte de la ville affichée pour chaque client renvoyé par la requête.Format de date ISO
'2026-03-14' comporte des zéros initiaux et se trie avant '2026-11-02' dans l’ordre des dates.I
Imbrication de fonctions
ROUND(COALESCE(amount, 0), 2), la valeur de repli est déterminée avant que la fonction d’arrondi ne reçoive son entrée.Indicateur numérique
CASE WHEN discount_pct > 0 THEN 1 ELSE 0 END attribue zéro aux remises manquantes ainsi qu’aux remises non positives.INSTR
INSTR('ana@example.com', '@') donne 4, tandis qu’une chaîne sans @ produit zéro.Intervalle (interval)
INTERVAL '1 month' à une DATE PostgreSQL renvoie un horodatage et suit sa règle de fin de mois.IS NULL
WHERE phone IS NULL extrait les clients sans téléphone enregistré sans comparer une valeur à NULL par égalité.J
Jour julien
julianday(end_date) - julianday(start_date) au lieu de soustraire directement des chaînes de dates ISO.L
LENGTH
LENGTH(' Bo ') donne 4 car les deux espaces aux extrémités comptent aussi bien que les deux lettres.Libellé de mois
'2026-03' distingue mars 2026 de mars 2025 dans l’affichage d’un rapport.Littéral
first_name || ' ' || last_name est un littéral textuel fourni par la requête.Logique à trois valeurs
FALSE AND UNKNOWN vaut FALSE, mais TRUE AND UNKNOWN reste UNKNOWN car la deuxième condition est indéterminée.M
Modèle de format
'%m/%d/%Y' pour un libellé de date américain ; TO_CHAR dans PostgreSQL utilise 'MM/DD/YYYY'.Modulo
135 % 60 donne les 15 minutes restantes après deux heures complètes.N
Nombre à virgule flottante
0.1 + 0.2 = 0.3 peut être faux parce que la somme des approximations stockées n’est pas égale à la même valeur.NULL
salary + bonus inconnu même si le salaire de l’employé est enregistré.NULLIF
NULLIF(visits, 0) conserve les nombres de visites positifs mais transforme zéro en diviseur manquant pour un taux.O
Ordre logique d’une requête
P
Plage semi-ouverte
ordered_at >= '2026-03-01' AND ordered_at < '2026-04-01' inclut tous les horodatages de mars.Position d’un caractère
'ana@example.com' est à la position 4, donc le domaine commence à la position 5.Priorité des opérateurs
10 + 3 * 2, donc le résultat est 16 et non 26.R
Rang de tri personnalisé
Remplissage
LPAD('42', 5, '0') dans PostgreSQL renvoie '00042', ce qui donne cinq caractères à un code court.REPLACE
REPLACE('555-0100', '-', '') supprime le tiret et affiche '5550100' sans modifier la table.Requête de rapport
ROUND
ROUND((price - cost) / price * 100, 1) pour afficher une marge à une décimale.S
Sous-chaîne
SUBSTR('Boston', 1, 3) renvoie 'Bos', en prenant trois caractères à partir de la première position.strftime
strftime('%m', '2026-03-14') renvoie '03', qui doit être comparé à du texte ou converti avant un usage numérique.T
Temps Unix
3600.0 pour conserver les fractions d’heure dans une durée.TIMESTAMP
'2026-03-31 14:05:00' est postérieur à minuit au début du 31 mars.TRIM
TRIM(' New York '), les deux espaces entre les mots restent dans le texte renvoyé.Type de données
'42' et l’entier 42 peuvent se ressembler dans une grille tout en se comportant différemment en SQL.U
UNKNOWN
bonus = NULL vaut UNKNOWN : elle ne peut donc pas identifier une prime manquante dans un filtre WHERE.UTC
V
Valeur de repli
Valeur de repli ELSE
ELSE 'large' sauf si une branche précédente teste explicitement total IS NULL.Valeur factice
NULLIF(phone, '') transforme une chaîne de téléphone vide en NULL avant de fournir un libellé d’affichage.Valeur limite
total < 50 est faux ; remplacer le test par total <= 50 le rend vrai.Vérification par échantillon
LIMIT 5 pendant la construction du rapport facilite le repérage d’un espace manquant ou d’une erreur de division entière.- 1Modèle relationnel
- 2Requêtes SELECT en SQL
- 3Colonnes calculées SQL
- 4Fonctions d’agrégation SQL
- 5Jointures SQL
- 6Créer des tables SQL
À propos de cette unité
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.