- Grands Pays (595)
Description
Vous disposez d'une table nommée World avec les colonnes suivantes :
| name | continent | area | population | gdp |
|---|---|---|---|---|
| Afghanistan | Asia | 652230 | 25500100 | 20343000 |
| Albania | Europe | 28748 | 2831741 | 12960000 |
| Algeria | Africa | 2381741 | 37100000 | 188681000 |
| Andorra | Europe | 468 | 78115 | 3712000 |
| Angola | Africa | 1246700 | 20609294 | 100990000 |
L'objectif est de sélectionner le nom (name), la population (population) et la superficie (area) de tous les pays considérés comme "grands". Un pays est grand s'il a une superficie supérieure à 3 000 000 km² OU une population supérieure à 25 000 000 habitants.
Résultat attendu :
| name | population | area |
|---|---|---|
| Afghanistan | 25500100 | 652230 |
| Algeria | 37100000 | 2381741 |
Solution
Pour cette requête, nous filtrons la table World en utilisant une clause WHERE combinant les deux critères avec l'opérateur logique OR.
SELECT
nom,
nombre_habitants,
superficie_km2
FROM
Pays
WHERE
superficie_km2 > 3000000
OR nombre_habitants > 25000000;
Schéma SQL
DROP TABLE IF EXISTS Pays;
CREATE TABLE Pays ( nom VARCHAR(255), continent VARCHAR(255), superficie_km2 INT, nombre_habitants INT, pib INT );
INSERT INTO Pays ( nom, continent, superficie_km2, nombre_habitants, pib )
VALUES
( 'Afghanistan', 'Asia', '652230', '25500100', '203430000' ),
( 'Albania', 'Europe', '28748', '2831741', '129600000' ),
( 'Algeria', 'Africa', '2381741', '37100000', '1886810000' ),
( 'Andorra', 'Europe', '468', '78115', '37120000' ),
( 'Angola', 'Africa', '1246700', '20609294', '1009900000' );
- Inverser les Sexes (627)
Description
On vous donne une table Employes contenant les informations suivantes :
| id | nom | sexe | salaire |
|---|---|---|---|
| 1 | A | m | 2500 |
| 2 | B | f | 1500 |
| 3 | C | m | 5500 |
| 4 | D | f | 500 |
Mettez à jour le champ sexe de manière à inverser 'm' et 'f' pour tous les enregistrements en une seule requête SQL.
Résultat attendu :
| id | nom | sexe | salaire |
|---|---|---|---|
| 1 | A | f | 2500 |
| 2 | B | m | 1500 |
| 3 | C | f | 5500 |
| 4 | D | m | 500 |
Solution
La manière la plus idiomatique d'inverser des valeurs binaires (comme 'm' et 'f') est d'utiliser une instruction UPDATE avec une expression CASE. Cela permet d'assigner la valeur 'f' si le sexe est 'm', et 'm' si le sexe est 'f' (ou toute autre valeur si non 'm', ce qui est suffisant ici).
UPDATE Employes
SET sexe = CASE
WHEN sexe = 'm' THEN 'f'
ELSE 'm'
END;
Schéma SQL
DROP TABLE IF EXISTS Employes;
CREATE TABLE Employes ( id INT, nom VARCHAR(100), sexe CHAR(1), salaire INT );
INSERT INTO Employes ( id, nom, sexe, salaire )
VALUES
( '1', 'A', 'm', '2500' ),
( '2', 'B', 'f', '1500' ),
( '3', 'C', 'm', '5500' ),
( '4', 'D', 'f', '500' );
- Films Non Ennuyeux (620)
Description
Vous avez une table Films avec les informations suivantes :
| id | film | description | evaluation |
|---|---|---|---|
| 1 | War | great 3D | 8.9 |
| 2 | Science | fiction | 8.5 |
| 3 | irish | boring | 6.2 |
| 4 | Ice song | Fantacy | 8.6 |
| 5 | House card | Interesting | 9.1 |
Trouvez tous les films ayant un identifiant (id) impair et dont la description n'est PAS 'boring'. Le résultat doit être trié par l'évaluation (evaluation) en ordre décroissant.
Résultat attendu :
| id | film | description | evaluation |
|---|---|---|---|
| 5 | House card | Interesting | 9.1 |
| 1 | War | great 3D | 8.9 |
Solution
Nous utiliserons une clause WHERE pour appliquer les conditions sur l'id et la description, puis une clause ORDER BY pour trier les résultats. Le modulo % est utilisé pour vérifier si l'id est impair.
SELECT
identifiant_film AS id,
titre_film AS movie,
resume_film AS description,
note_critique AS rating
FROM
Films
WHERE
MOD(identifiant_film, 2) = 1
AND resume_film != 'boring'
ORDER BY
note_critique DESC;
Schéma SQL
DROP TABLE IF EXISTS Films;
CREATE TABLE Films ( identifiant_film INT, titre_film VARCHAR(255), resume_film VARCHAR(255), note_critique FLOAT(2,1) );
INSERT INTO Films ( identifiant_film, titre_film, resume_film, note_critique )
VALUES
( 1, 'War', 'great 3D', 8.9 ),
( 2, 'Science', 'fiction', 8.5 ),
( 3, 'irish', 'boring', 6.2 ),
( 4, 'Ice song', 'Fantacy', 8.6 ),
( 5, 'House card', 'Interesting', 9.1 );
- Cours avec Plus de 5 Étudiants (596)
Description
On vous fournit une table Inscriptions qui associe des étudiants à des cours :
| etudiant | cours |
|---|---|
| A | Math |
| B | English |
| C | Math |
| D | Biology |
| E | Math |
| F | Computer |
| G | Math |
| H | Math |
| I | Math |
Votre tâche est de trouver tous les noms de cours (cours) qui comptent au moins cinq étudiants inscrits (distincts).
Résultat attendu :
| cours |
|---|
| Math |
Solution
Pour regrouper les enregistrements par cours et compter les étudiants, nous utilisons GROUP BY avec la colonne cours. Ensuite, la clause HAVING permet de filtrer ces groupes. Nous utilisons COUNT(DISTINCT nom_etudiant) pour s'assurer de ne compter que les étudiants uniques.
SELECT
nom_cours
FROM
Inscriptions
GROUP BY
nom_cours
HAVING
COUNT(DISTINCT nom_etudiant) >= 5;
Schéma SQL
DROP TABLE IF EXISTS Inscriptions;
CREATE TABLE Inscriptions ( nom_etudiant VARCHAR(255), nom_cours VARCHAR(255) );
INSERT INTO Inscriptions ( nom_etudiant, nom_cours )
VALUES
( 'A', 'Math' ),
( 'B', 'English' ),
( 'C', 'Math' ),
( 'D', 'Biology' ),
( 'E', 'Math' ),
( 'F', 'Computer' ),
( 'G', 'Math' ),
( 'H', 'Math' ),
( 'I', 'Math' );
- E-mails Dupliqués (182)
Description
Voici la table Utilisateurs, qui contient des identifiants et des adresses e-mail :
| id | |
|---|---|
| 1 | a@b.com |
| 2 | c@d.com |
| 3 | a@b.com |
Identifiez toutes les adresses e-mail qui apparaissent plus d'une fois dans la table.
Résultat attendu :
| a@b.com |
Solution
Comme pour la question précédente, l'approche consiste à regrouper les données par la colonne email et à utiliser la fonction d'agrégation COUNT(*) pour déterminer si un e-mail apparaît plusieurs fois. La clause HAVING filtre ensuite ces groupes.
SELECT
adresse_email
FROM
Utilisateurs
GROUP BY
adresse_email
HAVING
COUNT(*) >= 2;
Schéma SQL
DROP TABLE IF EXISTS Utilisateurs;
CREATE TABLE Utilisateurs ( id INT, adresse_email VARCHAR(255) );
INSERT INTO Utilisateurs ( id, adresse_email )
VALUES
( 1, 'a@b.com' ),
( 2, 'c@d.com' ),
( 3, 'a@b.com' );
- Suppression d'E-mails Dupliqués (196)
Description
En reprennant la table Utilisateurs :
| id | |
|---|---|
| 1 | john@example.com |
| 2 | bob@example.com |
| 3 | john@example.com |
Supprimez toutes les lignes où les adresses e-mail sont dupliquées, en ne conservant qu'une seule instance pour chaque e-mail unique (celle avec le plus petit id).
Résultat attendu :
| id | |
|---|---|
| 1 | john@example.com |
| 2 | bob@example.com |
Solution
Nous pouvons effectuer une suppression en utilisant une auto-jointure. L'idée est de joindre la table Utilisateurs avec elle-même, en cherchant les paires d'enregistrements ayant la même adresse e-mail mais des identifiants différents, puis de supprimer l'enregistrement avec le plus grand id.
DELETE p1
FROM
Utilisateurs p1
INNER JOIN
Utilisateurs p2 ON p1.adresse_email = p2.adresse_email AND p1.id_utilisateur > p2.id_utilisateur;
Schéma SQL
Identique à la question 182.
- Combiner Deux Tables (175)
Description
On vous donne deux tables, Personnes et Adresses :
Table Personnes :
| Nom Colonne | Type |
|---|---|
| PersonneId | int |
| Prenom | varchar |
| NomFamille | varchar |
PersonneId est la clé primaire.
Table Adresses :
| Nom Colonne | Type |
|---|---|
| AdresseId | int |
| PersonneId | int |
| Ville | varchar |
| Etat | varchar |
AdresseId est la clé primaire.
Sélectionnez Prenom, NomFamille, Ville et Etat pour chaque personne. Le résultat doit inclure toutes les personnes, même si elles n'ont pas d'adresse enregistrée.
Solution
Pour inclure toutes les personnes, y compris celles sans correspondance dans la table Adresses, une jointure externe gauche (LEFT JOIN) est nécessaire. La table Personnes doit être placée à gauche de la jointure.
SELECT
P.prenom_personne,
P.nom_famille_personne,
A.ville_adresse,
A.etat_adresse
FROM
Personnes P
LEFT JOIN
Adresses A ON P.id_personne = A.id_personne;
Schéma SQL
DROP TABLE IF EXISTS Personnes;
CREATE TABLE Personnes ( id_personne INT, prenom_personne VARCHAR(255), nom_famille_personne VARCHAR(255) );
DROP TABLE IF EXISTS Adresses;
CREATE TABLE Adresses ( id_adresse INT, id_personne INT, ville_adresse VARCHAR(255), etat_adresse VARCHAR(255) );
INSERT INTO Personnes ( id_personne, nom_famille_personne, prenom_personne )
VALUES
( 1, 'Wang', 'Allen' );
INSERT INTO Adresses ( id_adresse, id_personne, ville_adresse, etat_adresse )
VALUES
( 1, 2, 'New York City', 'New York' );
- Employés Gagnant Plus que leurs Managers (181)
Description
Voici la table Personnel :
| Id | Nom | Salaire | ManagerId |
|---|---|---|---|
| 1 | Joe | 70000 | 3 |
| 2 | Henry | 80000 | 4 |
| 3 | Sam | 60000 | NULL |
| 4 | Max | 90000 | NULL |
Votre objectif est de trouver le nom de tous les employés dont le salaire est strictement supérieur à celui de leur manager.
Solution
Nous utilisnos une auto-jointure sur la table Personnel, en joignant les employés (e) à leurs managers (m) via la colonne manager_id. Ensuite, nous appliquons une condition pour comparer leurs salaires.
SELECT
e.nom_employe AS Employe
FROM
Personnel e
INNER JOIN
Personnel m ON e.manager_id = m.id_employe
WHERE
e.salaire_employe > m.salaire_employe;
Schéma SQL
DROP TABLE IF EXISTS Personnel;
CREATE TABLE Personnel ( id_employe INT, nom_employe VARCHAR(255), salaire_employe INT, manager_id INT );
INSERT INTO Personnel ( id_employe, nom_employe, salaire_employe, manager_id )
VALUES
( 1, 'Joe', 70000, 3 ),
( 2, 'Henry', 80000, 4 ),
( 3, 'Sam', 60000, NULL ),
( 4, 'Max', 90000, NULL );
- Clients Sans Commandes (183)
Description
Vous disposez de deux tables : Clients et Commandes.
Table Clients :
| Id | Nom |
|---|---|
| 1 | Joe |
| 2 | Henry |
| 3 | Sam |
| 4 | Max |
Table Commandes :
| Id | ClientId |
|---|---|
| 1 | 3 |
| 2 | 1 |
Identifiez les noms des clients qui n'ont jamais passé de commande.
Résultat attendu :
| Clients |
|---|
| Henry |
| Max |
Solution
Une méthode efficace pour trouver les enregistrements qui n'ont pas de correspondance dans une autre table est d'utiliser une sous-requête avec NOT EXISTS. Cela vérifie l'absence de commandes pour chaque client.
SELECT
C.nom_client AS Clients
FROM
Clients C
WHERE NOT EXISTS (
SELECT 1
FROM Commandes O
WHERE O.id_client = C.id_client
);
Schéma SQL
DROP TABLE IF EXISTS Clients;
CREATE TABLE Clients ( id_client INT, nom_client VARCHAR(255) );
DROP TABLE IF EXISTS Commandes;
CREATE TABLE Commandes ( id_commande INT, id_client INT );
INSERT INTO Clients ( id_client, nom_client )
VALUES
( 1, 'Joe' ),
( 2, 'Henry' ),
( 3, 'Sam' ),
( 4, 'Max' );
INSERT INTO Commandes ( id_commande, id_client )
VALUES
( 1, 3 ),
( 2, 1 );
- Salaire le Plus Élevé par Département (184)
Description
Vous avez deux tables, Employes et Departements.
Table Employes :
| Id | Nom | Salaire | DepartementId |
|---|---|---|---|
| 1 | Joe | 70000 | 1 |
| 2 | Henry | 80000 | 2 |
| 3 | Sam | 60000 | 2 |
| 4 | Max | 90000 | 1 |
Table Departements :
| Id | Nom |
|---|---|
| 1 | IT |
| 2 | Sales |
Pour chaque département, trouvez le ou les employés qui ont le salaire le plus élevé. Le résultat doit afficher le nom du département, le nom de l'employé et son salaire.
Résultat attendu :
| Departement | Employe | Salaire |
|---|---|---|
| IT | Max | 90000 |
| Sales | Henry | 80000 |
Solution
L'utilisation des fonctions de fenêtre SQL (spécifiquement DENSE_RANK()) simplifie grandement ce type de requête. Nous pouvons classer les employés par salaire au sein de chaque département, puis filtrer pour ne garder que ceux ayant le rang 1.
WITH SalairesClasses AS (
SELECT
e.id_departement,
e.nom_employe,
e.salaire_employe,
DENSE_RANK() OVER (PARTITION BY e.id_departement ORDER BY e.salaire_employe DESC) AS rang_salaire
FROM
Employes e
)
SELECT
d.nom_departement AS Departement,
sc.nom_employe AS Employe,
sc.salaire_employe AS Salaire
FROM
SalairesClasses sc
JOIN
Departements d ON sc.id_departement = d.id_departement
WHERE
sc.rang_salaire = 1;
Schéma SQL
DROP TABLE IF EXISTS Employes;
CREATE TABLE Employes ( id_employe INT, nom_employe VARCHAR(255), salaire_employe INT, id_departement INT );
DROP TABLE IF EXISTS Departements;
CREATE TABLE Departements ( id_departement INT, nom_departement VARCHAR(255) );
INSERT INTO Employes ( id_employe, nom_employe, salaire_employe, id_departement )
VALUES
( 1, 'Joe', 70000, 1 ),
( 2, 'Henry', 80000, 2 ),
( 3, 'Sam', 60000, 2 ),
( 4, 'Max', 90000, 1 );
INSERT INTO Departements ( id_departement, nom_departement )
VALUES
( 1, 'IT' ),
( 2, 'Sales' );
- Deuxième Salaire le Plus Élevé (176)
Description
Table Salaires :
| Id | Salaire |
|---|---|
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
Trouvez le deuxième salaire le plus élevé. Si aucun deuxième salaire n'existe (par exemple, un seul employé), la requête doit retourner NULL.
Résultat attendu :
| DeuxiemeSalaireLePlusEleve |
|---|
| 200 |
Solution
Nous pouvons utiliser les fonctions de fenêtre, spécifiquement DENSE_RANK(), pour classer les salaires de manière distincte. Ensuite, nous sélectionnons le salaire correspondant au rang 2. L'utilisation de MAX() sur le résultat garantit que si aucun deuxième salaire n'est trouvé, NULL est retourné.
WITH ClassementSalaires AS (
SELECT
salaire_emp AS Salaire,
DENSE_RANK() OVER (ORDER BY salaire_emp DESC) AS rang_salaire
FROM
Employes
)
SELECT
MAX(CASE WHEN rang_salaire = 2 THEN Salaire ELSE NULL END) AS DeuxiemeSalaireLePlusEleve
FROM
ClassementSalaires;
Schéma SQL
DROP TABLE IF EXISTS Employes;
CREATE TABLE Employes ( id_employe INT, salaire_emp INT );
INSERT INTO Employes ( id_employe, salaire_emp )
VALUES
( 1, 100 ),
( 2, 200 ),
( 3, 300 );
- N-ième Salaire le Plus Élevé (177)
Description
Écrivez une fonction SQL pour récupérer le N-ième salaire le plus élevé. La table est la même que celle de la question précédente (Employes).
Solution
Nous allons créer une fonction qui prend un entier N en paramètre. À l'intérieur de la fonction, nous utiliserons la fonction de fenêtre DENSE_RANK() pour classer les salaires et sélectionner le salaire correspondant au rang N.
CREATE FUNCTION ObtenirNiemeSalaireLePlusEleve (rang_souhaite INT) RETURNS INT
BEGIN
DECLARE resultat_salaire INT;
WITH SalairesClasses AS (
SELECT
salaire_emp,
DENSE_RANK() OVER (ORDER BY salaire_emp DESC) AS rang_effectif
FROM
Employes
)
SELECT DISTINCT salaire_emp
INTO resultat_salaire
FROM SalairesClasses
WHERE rang_effectif = rang_souhaite;
RETURN resultat_salaire;
END;
Schéma SQL
Identique à la question 176.
- Classement des Scores (178)
Description
Voici la table ResultatsExamens :
| Id | Score |
|---|---|
| 1 | 3.50 |
| 2 | 3.65 |
| 3 | 4.00 |
| 4 | 3.85 |
| 5 | 4.00 |
| 6 | 3.65 |
Classez les scores du plus élevé au moins élevé. Les scores égaux doivent avoir le même rang, et il ne doit pas y avoir de "trous" dans la séquence des rangs (c'est-à-dire un classement de type "dense").
Résultat attendu :
| Score | Rang |
|---|---|
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
Solution
La fonction de fenêtre DENSE_RANK() est parfaitement adaptée à ce problème. Elle attribue un rang à chaque ligne en fonction de son ordre dans un groupe partitionné, sans sauter de rangs en cas d'égalité.
SELECT
score_etudiant AS Score,
DENSE_RANK() OVER (ORDER BY score_etudiant DESC) AS Rang
FROM
ResultatsExamens
ORDER BY
Score DESC;
Schéma SQL
DROP TABLE IF EXISTS ResultatsExamens;
CREATE TABLE ResultatsExamens ( id_enregistrement INT, score_etudiant DECIMAL(3,2) );
INSERT INTO ResultatsExamens ( id_enregistrement, score_etudiant )
VALUES
( 1, 4.1 ),
( 2, 4.1 ),
( 3, 4.2 ),
( 4, 4.2 ),
( 5, 4.3 ),
( 6, 4.3 );
- Nombres Consécutifs (180)
Description
Vous avez une table HistoriqueNombres :
| Id | Num |
|---|---|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
Trouvez tous les nombres qui apparaissent au moins trois fois consécutivement.
Résultat attendu :
| NombresConsecutifs |
|---|
| 1 |
Solution
Pour identifier les nombres consécutifs, nous pouvons utiliser la fonction de fenêtre LAG() pour accéder aux valeurs des lignes précédentes. Nous vérifions ensuite si le nombre actuel est le même que les deux précédents.
WITH NumerosSequences AS (
SELECT
numero_valeur,
LAG(numero_valeur, 1) OVER (ORDER BY id_enregistrement) AS precedent_un,
LAG(numero_valeur, 2) OVER (ORDER BY id_enregistrement) AS precedent_deux
FROM
HistoriqueNombres
)
SELECT DISTINCT
numero_valeur AS NombresConsecutifs
FROM
NumerosSequences
WHERE
numero_valeur = precedent_un
AND numero_valeur = precedent_deux;
Schéma SQL
DROP TABLE IF EXISTS HistoriqueNombres;
CREATE TABLE HistoriqueNombres ( id_enregistrement INT, numero_valeur INT );
INSERT INTO HistoriqueNombres ( id_enregistrement, numero_valeur )
VALUES
( 1, 1 ),
( 2, 1 ),
( 3, 1 ),
( 4, 2 ),
( 5, 1 ),
( 6, 2 ),
( 7, 2 );
- Échanger les Places (626)
Description
La table Sieges contient un identifiant de siège (id) et le nom de l'étudiant (student) qui l'occupe :
| id | student |
|---|---|
| 1 | Abbot |
| 2 | Doris |
| 3 | Emerson |
| 4 | Green |
| 5 | Jeames |
Échangez les étudiants des sièges adjacents. Si le nombre total de sièges est impair, le dernier siège (avec l'id le plus élevé) doit rester inchangé. Le résultat doit être ordonné par id.
Résultat attendu :
| id | student |
|---|---|
| 1 | Doris |
| 2 | Abbot |
| 3 | Green |
| 4 | Emerson |
| 5 | Jeames |
Solution
Une instruction SELECT avec une clause CASE permet de gérer les différentes logiques d'échange. Pour un id impair qui n'est pas le dernier, on ajoute 1. Pour un id pair, on soustrait 1. Le dernier id impair reste tel quel.
SELECT
CASE
-- Si l'id est impair et c'est le dernier siège, il ne bouge pas
WHEN MOD(s.id_siege, 2) = 1 AND s.id_siege = (SELECT MAX(sub.id_siege) FROM Sieges sub) THEN s.id_siege
-- Si l'id est impair (et non le dernier), il prend l'id suivant
WHEN MOD(s.id_siege, 2) = 1 THEN s.id_siege + 1
-- Si l'id est pair, il prend l'id précédent
ELSE s.id_siege - 1
END AS id,
s.nom_etudiant AS student
FROM
Sieges s
ORDER BY
id ASC;
Schéma SQL
DROP TABLE IF EXISTS Sieges;
CREATE TABLE Sieges ( id_siege INT, nom_etudiant VARCHAR(255) );
INSERT INTO Sieges ( id_siege, nom_etudiant )
VALUES
( '1', 'Abbot' ),
( '2', 'Doris' ),
( '3', 'Emerson' ),
( '4', 'Green' ),
( '5', 'Jeames' );