ajout de tous les cours et TP préparés cet été
This commit is contained in:
464
SQL/CORRIGE.md
Normal file
464
SQL/CORRIGE.md
Normal file
@@ -0,0 +1,464 @@
|
||||
# Corrigé des exercices — SQL
|
||||
|
||||
---
|
||||
|
||||
## Exercice 1 : Requêtes SELECT simples
|
||||
|
||||
1. **Tous les livres de la table LIVRES.**
|
||||
```sql
|
||||
SELECT * FROM LIVRES;
|
||||
```
|
||||
|
||||
2. **Les titres et années de publication de tous les livres.**
|
||||
```sql
|
||||
SELECT titre, ann_publi FROM LIVRES;
|
||||
```
|
||||
|
||||
3. **Les noms et prénoms de tous les auteurs.**
|
||||
```sql
|
||||
SELECT nom, prenom FROM AUTEURS;
|
||||
```
|
||||
|
||||
4. **Les titres des livres publiés après 1950.**
|
||||
```sql
|
||||
SELECT titre FROM LIVRES WHERE ann_publi > 1950;
|
||||
```
|
||||
|
||||
5. **Les titres des livres du genre "dystopie".**
|
||||
```sql
|
||||
SELECT titre FROM LIVRES WHERE genre = 'dystopie';
|
||||
```
|
||||
|
||||
6. **Les auteurs de nationalité française.**
|
||||
```sql
|
||||
SELECT * FROM AUTEURS WHERE nationalite = 'français';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exercice 2 : Filtres et conditions
|
||||
|
||||
1. **Les livres publiés entre 1940 et 1960 (inclus).**
|
||||
```sql
|
||||
SELECT * FROM LIVRES WHERE ann_publi BETWEEN 1940 AND 1960;
|
||||
-- ou
|
||||
SELECT * FROM LIVRES WHERE ann_publi >= 1940 AND ann_publi <= 1960;
|
||||
```
|
||||
|
||||
2. **Les livres ayant plus de 300 pages.**
|
||||
```sql
|
||||
SELECT * FROM LIVRES WHERE nb_pages > 300;
|
||||
```
|
||||
|
||||
3. **Les auteurs nés après 1900 et de nationalité américaine.**
|
||||
```sql
|
||||
SELECT * FROM AUTEURS
|
||||
WHERE ann_naissance > 1900 AND nationalite = 'américain';
|
||||
```
|
||||
|
||||
4. **Les livres dont le titre contient le mot "Terre".**
|
||||
```sql
|
||||
SELECT * FROM LIVRES WHERE titre LIKE '%Terre%';
|
||||
```
|
||||
|
||||
5. **Les livres qui ne sont pas du genre "SF".**
|
||||
```sql
|
||||
SELECT * FROM LIVRES WHERE genre <> 'SF';
|
||||
-- ou
|
||||
SELECT * FROM LIVRES WHERE genre != 'SF';
|
||||
-- ou
|
||||
SELECT * FROM LIVRES WHERE NOT genre = 'SF';
|
||||
```
|
||||
|
||||
6. **Les auteurs dont le prénom commence par la lettre "R".**
|
||||
```sql
|
||||
SELECT * FROM AUTEURS WHERE prenom LIKE 'R%';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exercice 3 : Tri et limitation
|
||||
|
||||
1. **Tous les livres triés par année de publication (du plus ancien au plus récent).**
|
||||
```sql
|
||||
SELECT * FROM LIVRES ORDER BY ann_publi ASC;
|
||||
-- ou simplement
|
||||
SELECT * FROM LIVRES ORDER BY ann_publi;
|
||||
```
|
||||
|
||||
2. **Les 5 livres les plus récents.**
|
||||
```sql
|
||||
SELECT * FROM LIVRES ORDER BY ann_publi DESC LIMIT 5;
|
||||
```
|
||||
|
||||
3. **Les auteurs triés par année de naissance décroissante.**
|
||||
```sql
|
||||
SELECT * FROM AUTEURS ORDER BY ann_naissance DESC;
|
||||
```
|
||||
|
||||
4. **Les 3 livres ayant le plus de pages.**
|
||||
```sql
|
||||
SELECT * FROM LIVRES ORDER BY nb_pages DESC LIMIT 3;
|
||||
```
|
||||
|
||||
5. **Les livres triés par genre, puis par titre alphabétique.**
|
||||
```sql
|
||||
SELECT * FROM LIVRES ORDER BY genre ASC, titre ASC;
|
||||
```
|
||||
|
||||
6. **La liste des genres sans doublons.**
|
||||
```sql
|
||||
SELECT DISTINCT genre FROM LIVRES;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exercice 4 : Fonctions d'agrégation
|
||||
|
||||
1. **Le nombre total de livres dans la base.**
|
||||
```sql
|
||||
SELECT COUNT(*) FROM LIVRES;
|
||||
-- Résultat : 12
|
||||
```
|
||||
|
||||
2. **Le nombre de pages du livre le plus long.**
|
||||
```sql
|
||||
SELECT MAX(nb_pages) FROM LIVRES;
|
||||
-- Résultat : 896 (Dune)
|
||||
```
|
||||
|
||||
3. **L'année de publication du livre le plus ancien.**
|
||||
```sql
|
||||
SELECT MIN(ann_publi) FROM LIVRES;
|
||||
-- Résultat : 1865 (De la Terre à la Lune)
|
||||
```
|
||||
|
||||
4. **Le nombre moyen de pages des livres.**
|
||||
```sql
|
||||
SELECT AVG(nb_pages) FROM LIVRES;
|
||||
-- Résultat : environ 333.25
|
||||
```
|
||||
|
||||
5. **Le nombre de livres par genre.**
|
||||
```sql
|
||||
SELECT genre, COUNT(*) AS nb_livres
|
||||
FROM LIVRES
|
||||
GROUP BY genre;
|
||||
```
|
||||
Résultat :
|
||||
| genre | nb_livres |
|
||||
|-------|-----------|
|
||||
| aventure | 2 |
|
||||
| dystopie | 3 |
|
||||
| post-apo | 1 |
|
||||
| SF | 4 |
|
||||
| space opera | 2 |
|
||||
|
||||
6. **Le nombre total de pages de tous les livres de Jules Verne (id_auteur = 8).**
|
||||
```sql
|
||||
SELECT SUM(nb_pages) FROM LIVRES WHERE id_auteur = 8;
|
||||
-- Résultat : 672 (192 + 480)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exercice 5 : GROUP BY et HAVING
|
||||
|
||||
1. **Le nombre de livres écrits par chaque auteur.**
|
||||
```sql
|
||||
SELECT id_auteur, COUNT(*) AS nb_livres
|
||||
FROM LIVRES
|
||||
GROUP BY id_auteur;
|
||||
```
|
||||
|
||||
2. **Le nombre moyen de pages par genre.**
|
||||
```sql
|
||||
SELECT genre, AVG(nb_pages) AS moy_pages
|
||||
FROM LIVRES
|
||||
GROUP BY genre;
|
||||
```
|
||||
|
||||
3. **Les genres ayant plus de 2 livres.**
|
||||
```sql
|
||||
SELECT genre, COUNT(*) AS nb_livres
|
||||
FROM LIVRES
|
||||
GROUP BY genre
|
||||
HAVING COUNT(*) > 2;
|
||||
```
|
||||
Résultat : dystopie (3), SF (4)
|
||||
|
||||
4. **Les auteurs ayant écrit au moins 2 livres.**
|
||||
```sql
|
||||
SELECT id_auteur, COUNT(*) AS nb_livres
|
||||
FROM LIVRES
|
||||
GROUP BY id_auteur
|
||||
HAVING COUNT(*) >= 2;
|
||||
```
|
||||
Résultat : id_auteur 3, 5, 7, 8 (Asimov, Bradbury, Barjavel, Verne)
|
||||
|
||||
5. **L'année de publication du premier livre de chaque auteur.**
|
||||
```sql
|
||||
SELECT id_auteur, MIN(ann_publi) AS premier_livre
|
||||
FROM LIVRES
|
||||
GROUP BY id_auteur;
|
||||
```
|
||||
|
||||
6. **Les genres dont la moyenne de pages dépasse 250.**
|
||||
```sql
|
||||
SELECT genre, AVG(nb_pages) AS moy_pages
|
||||
FROM LIVRES
|
||||
GROUP BY genre
|
||||
HAVING AVG(nb_pages) > 250;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exercice 6 : Jointures
|
||||
|
||||
1. **Les titres des livres avec le nom et prénom de leur auteur.**
|
||||
```sql
|
||||
SELECT L.titre, A.nom, A.prenom
|
||||
FROM LIVRES L
|
||||
INNER JOIN AUTEURS A ON L.id_auteur = A.id;
|
||||
```
|
||||
|
||||
2. **Les titres des livres écrits par des auteurs français.**
|
||||
```sql
|
||||
SELECT L.titre
|
||||
FROM LIVRES L
|
||||
INNER JOIN AUTEURS A ON L.id_auteur = A.id
|
||||
WHERE A.nationalite = 'français';
|
||||
```
|
||||
Résultat : La nuit des temps, Ravage, De la Terre à la Lune, Vingt mille lieues sous les mers
|
||||
|
||||
3. **Les titres et auteurs des livres du genre "dystopie", triés par année.**
|
||||
```sql
|
||||
SELECT L.titre, A.nom, A.prenom, L.ann_publi
|
||||
FROM LIVRES L
|
||||
INNER JOIN AUTEURS A ON L.id_auteur = A.id
|
||||
WHERE L.genre = 'dystopie'
|
||||
ORDER BY L.ann_publi;
|
||||
```
|
||||
|
||||
4. **Le nom des auteurs ayant écrit des livres de plus de 400 pages.**
|
||||
```sql
|
||||
SELECT DISTINCT A.nom, A.prenom
|
||||
FROM AUTEURS A
|
||||
INNER JOIN LIVRES L ON A.id = L.id_auteur
|
||||
WHERE L.nb_pages > 400;
|
||||
```
|
||||
Résultat : Herbert Frank, Verne Jules
|
||||
|
||||
5. **Les livres avec le nom de l'auteur, pour les auteurs américains nés après 1910.**
|
||||
```sql
|
||||
SELECT L.titre, A.nom
|
||||
FROM LIVRES L
|
||||
INNER JOIN AUTEURS A ON L.id_auteur = A.id
|
||||
WHERE A.nationalite = 'américain' AND A.ann_naissance > 1910;
|
||||
```
|
||||
|
||||
6. **Pour chaque nationalité, le nombre de livres écrits.**
|
||||
```sql
|
||||
SELECT A.nationalite, COUNT(*) AS nb_livres
|
||||
FROM AUTEURS A
|
||||
INNER JOIN LIVRES L ON A.id = L.id_auteur
|
||||
GROUP BY A.nationalite;
|
||||
```
|
||||
Résultat :
|
||||
| nationalite | nb_livres |
|
||||
|-------------|-----------|
|
||||
| américain | 6 |
|
||||
| britannique | 2 |
|
||||
| français | 4 |
|
||||
|
||||
---
|
||||
|
||||
## Exercice 7 : Requêtes complexes
|
||||
|
||||
1. **Le titre du livre le plus long de chaque auteur, avec le nom de l'auteur.**
|
||||
```sql
|
||||
SELECT A.nom, A.prenom, L.titre, L.nb_pages
|
||||
FROM LIVRES L
|
||||
INNER JOIN AUTEURS A ON L.id_auteur = A.id
|
||||
WHERE L.nb_pages = (
|
||||
SELECT MAX(nb_pages)
|
||||
FROM LIVRES
|
||||
WHERE id_auteur = L.id_auteur
|
||||
);
|
||||
```
|
||||
|
||||
2. **Les auteurs n'ayant écrit qu'un seul livre.**
|
||||
```sql
|
||||
SELECT A.nom, A.prenom, L.titre
|
||||
FROM AUTEURS A
|
||||
INNER JOIN LIVRES L ON A.id = L.id_auteur
|
||||
WHERE A.id IN (
|
||||
SELECT id_auteur
|
||||
FROM LIVRES
|
||||
GROUP BY id_auteur
|
||||
HAVING COUNT(*) = 1
|
||||
);
|
||||
```
|
||||
|
||||
3. **Le nombre moyen de pages des livres par nationalité d'auteur.**
|
||||
```sql
|
||||
SELECT A.nationalite, AVG(L.nb_pages) AS moy_pages
|
||||
FROM AUTEURS A
|
||||
INNER JOIN LIVRES L ON A.id = L.id_auteur
|
||||
GROUP BY A.nationalite;
|
||||
```
|
||||
|
||||
4. **Les genres pour lesquels tous les livres ont été publiés après 1940.**
|
||||
```sql
|
||||
SELECT genre
|
||||
FROM LIVRES
|
||||
GROUP BY genre
|
||||
HAVING MIN(ann_publi) > 1940;
|
||||
```
|
||||
Résultat : dystopie (min 1931... non!), SF (min 1950), space opera (min 1951)
|
||||
|
||||
Note : En vérifiant les données, "Le meilleur des mondes" (dystopie) est de 1931, donc dystopie ne correspond pas. Les genres valides sont : SF, space opera, post-apo.
|
||||
|
||||
5. **Le nom complet des auteurs et le nombre total de pages qu'ils ont écrites.**
|
||||
```sql
|
||||
SELECT A.prenom || ' ' || A.nom AS nom_complet, SUM(L.nb_pages) AS total_pages
|
||||
FROM AUTEURS A
|
||||
INNER JOIN LIVRES L ON A.id = L.id_auteur
|
||||
GROUP BY A.id
|
||||
ORDER BY total_pages DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exercice 8 : INSERT, UPDATE, DELETE
|
||||
|
||||
1. **Ajouter l'auteur Ursula K. Le Guin.**
|
||||
```sql
|
||||
INSERT INTO AUTEURS (id, nom, prenom, nationalite, ann_naissance)
|
||||
VALUES (9, 'Le Guin', 'Ursula K.', 'américain', 1929);
|
||||
```
|
||||
|
||||
2. **Ajouter le livre "La Main gauche de la nuit".**
|
||||
```sql
|
||||
INSERT INTO LIVRES (id, titre, id_auteur, ann_publi, genre, nb_pages)
|
||||
VALUES (13, 'La Main gauche de la nuit', 9, 1969, 'SF', 304);
|
||||
```
|
||||
|
||||
3. **Changer le genre de "Dune" en "SF".**
|
||||
```sql
|
||||
UPDATE LIVRES
|
||||
SET genre = 'SF'
|
||||
WHERE titre = 'Dune';
|
||||
```
|
||||
|
||||
4. **Augmenter de 10% le nombre de pages de tous les livres de Jules Verne.**
|
||||
```sql
|
||||
UPDATE LIVRES
|
||||
SET nb_pages = nb_pages * 1.1
|
||||
WHERE id_auteur = 8;
|
||||
```
|
||||
|
||||
5. **Supprimer tous les livres publiés avant 1900.**
|
||||
```sql
|
||||
DELETE FROM LIVRES
|
||||
WHERE ann_publi < 1900;
|
||||
```
|
||||
Note : Cela supprimera "De la Terre à la Lune" (1865) et "Vingt mille lieues sous les mers" (1870).
|
||||
|
||||
---
|
||||
|
||||
## Exercice 9 : Création de tables
|
||||
|
||||
1. **Créer la table EMPRUNTS.**
|
||||
```sql
|
||||
CREATE TABLE EMPRUNTS (
|
||||
id INTEGER PRIMARY KEY,
|
||||
id_livre INTEGER,
|
||||
id_adherent INTEGER,
|
||||
date_emprunt DATE,
|
||||
date_retour DATE,
|
||||
FOREIGN KEY (id_livre) REFERENCES LIVRES(id)
|
||||
);
|
||||
```
|
||||
|
||||
2. **Créer la table EDITEURS.**
|
||||
```sql
|
||||
CREATE TABLE EDITEURS (
|
||||
id INTEGER PRIMARY KEY,
|
||||
nom TEXT,
|
||||
pays TEXT,
|
||||
ann_creation INTEGER
|
||||
);
|
||||
```
|
||||
|
||||
3. **Ajouter une colonne id_editeur à la table LIVRES.**
|
||||
```sql
|
||||
ALTER TABLE LIVRES ADD COLUMN id_editeur INTEGER REFERENCES EDITEURS(id);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exercice 10 : Analyse de requêtes
|
||||
|
||||
1. **Requête avec sous-requête MIN :**
|
||||
```sql
|
||||
SELECT titre FROM LIVRES WHERE ann_publi = (SELECT MIN(ann_publi) FROM LIVRES);
|
||||
```
|
||||
**Explication :** Cette requête retourne le titre du livre le plus ancien de la base. La sous-requête trouve l'année minimale, puis la requête principale sélectionne le(s) livre(s) publié(s) cette année-là.
|
||||
|
||||
**Résultat :** "De la Terre à la Lune" (1865)
|
||||
|
||||
2. **Requête complexe avec double sous-requête :**
|
||||
```sql
|
||||
SELECT A.nom, COUNT(*)
|
||||
FROM AUTEURS A
|
||||
INNER JOIN LIVRES L ON A.id = L.id_auteur
|
||||
GROUP BY A.id
|
||||
HAVING COUNT(*) = (SELECT MAX(cnt) FROM (SELECT COUNT(*) as cnt FROM LIVRES GROUP BY id_auteur));
|
||||
```
|
||||
**Explication :** Cette requête retourne le(s) auteur(s) ayant écrit le plus grand nombre de livres. La sous-requête interne compte les livres par auteur, la sous-requête externe trouve le maximum, et la requête principale affiche les auteurs atteignant ce maximum.
|
||||
|
||||
**Résultat :** Les auteurs avec 2 livres chacun (Asimov, Bradbury, Barjavel, Verne)
|
||||
|
||||
3. **Requête avec NOT IN :**
|
||||
```sql
|
||||
SELECT DISTINCT genre FROM LIVRES WHERE genre NOT IN (SELECT genre FROM LIVRES WHERE ann_publi < 1950);
|
||||
```
|
||||
**Explication :** Cette requête retourne les genres pour lesquels AUCUN livre n'a été publié avant 1950. La sous-requête trouve les genres ayant au moins un livre avant 1950, puis la requête principale exclut ces genres.
|
||||
|
||||
**Résultat :** Les genres dont tous les livres sont de 1950 ou après (SF, space opera, potentiellement post-apo selon les données)
|
||||
|
||||
---
|
||||
|
||||
## Exercice 11 : QCM
|
||||
|
||||
1. **Quelle clause permet de filtrer les résultats d'un GROUP BY ?**
|
||||
- **Réponse : c) HAVING**
|
||||
|
||||
2. **Quelle est la différence entre WHERE et HAVING ?**
|
||||
- **Réponse : b) WHERE filtre avant GROUP BY, HAVING filtre après**
|
||||
|
||||
Explication : WHERE filtre les lignes individuelles avant le regroupement. HAVING filtre les groupes après le regroupement et permet d'utiliser des fonctions d'agrégation.
|
||||
|
||||
3. **Que retourne `SELECT COUNT(*) FROM LIVRES WHERE 1=0;` ?**
|
||||
- **Réponse : c) 0**
|
||||
|
||||
Explication : La condition `1=0` est toujours fausse, donc aucune ligne n'est sélectionnée. COUNT(*) sur un ensemble vide retourne 0 (pas NULL, pas d'erreur).
|
||||
|
||||
4. **Quel type de jointure retourne tous les enregistrements de la table de gauche ?**
|
||||
- **Réponse : b) LEFT JOIN**
|
||||
|
||||
Explication : LEFT JOIN retourne toutes les lignes de la table de gauche, même si elles n'ont pas de correspondance dans la table de droite (avec NULL pour les colonnes de droite).
|
||||
|
||||
5. **Quelle fonction d'agrégation ignore les valeurs NULL ?**
|
||||
- **Réponse : b) COUNT(colonne)**
|
||||
|
||||
Explication : `COUNT(*)` compte toutes les lignes, y compris celles avec des NULL. `COUNT(colonne)` ne compte que les valeurs non NULL de cette colonne.
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
407
SQL/Corrige_TP_Streaming_Musical.md
Normal file
407
SQL/Corrige_TP_Streaming_Musical.md
Normal file
@@ -0,0 +1,407 @@
|
||||
# Corrigé du TP : Base de données d'un service de streaming musical
|
||||
|
||||
---
|
||||
|
||||
## Partie 1 : Schéma relationnel
|
||||
|
||||
```
|
||||
ARTISTES ALBUMS
|
||||
+----+---------+ +----+--------+-----------+
|
||||
| id | nom | | id | titre | id_artiste|
|
||||
| PK | ... |<─────────────────| PK | ... | FK |
|
||||
+----+---------+ +----+--------+-----------+
|
||||
│
|
||||
│
|
||||
▼
|
||||
TITRES
|
||||
+----+------+----------+
|
||||
| id | nom | id_album |
|
||||
| PK | ... | FK |
|
||||
+----+------+----------+
|
||||
│
|
||||
│
|
||||
UTILISATEURS │
|
||||
+----+--------+ │
|
||||
| id | pseudo | │
|
||||
| PK | ... | │
|
||||
+----+--------+ │
|
||||
│ │
|
||||
│ ECOUTES │
|
||||
│ +----+--------------+-----+
|
||||
└────────>| id | id_utilisateur| id_titre |
|
||||
| PK | FK | FK |
|
||||
+----+--------------+----------+
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 2 : Requêtes de base
|
||||
|
||||
**1. Tous les artistes**
|
||||
```sql
|
||||
SELECT * FROM ARTISTES;
|
||||
```
|
||||
|
||||
**2. Artistes français**
|
||||
```sql
|
||||
SELECT nom, pays FROM ARTISTES WHERE pays = 'France';
|
||||
```
|
||||
Résultat : Daft Punk, PNL, Aya Nakamura
|
||||
|
||||
**3. Albums sortis après 2015**
|
||||
```sql
|
||||
SELECT titre FROM ALBUMS WHERE ann_sortie > 2015;
|
||||
```
|
||||
|
||||
**4. Utilisateurs premium**
|
||||
```sql
|
||||
SELECT pseudo FROM UTILISATEURS WHERE type_abo = 'premium';
|
||||
```
|
||||
Résultat : music_lover_33, kevin_hiphop, thomas_electro, jp_kpop
|
||||
|
||||
**5. Titres de plus de 4 minutes**
|
||||
```sql
|
||||
SELECT nom, duree_sec FROM TITRES WHERE duree_sec > 240;
|
||||
```
|
||||
|
||||
**6. Artistes Hip-Hop ou Pop**
|
||||
```sql
|
||||
SELECT * FROM ARTISTES WHERE genre_principal IN ('Hip-Hop', 'Pop');
|
||||
-- ou
|
||||
SELECT * FROM ARTISTES WHERE genre_principal = 'Hip-Hop' OR genre_principal = 'Pop';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 3 : Requêtes avec jointures
|
||||
|
||||
**7. Titres avec nom d'album**
|
||||
```sql
|
||||
SELECT T.nom AS titre, A.titre AS album
|
||||
FROM TITRES T
|
||||
INNER JOIN ALBUMS A ON T.id_album = A.id;
|
||||
```
|
||||
|
||||
**8. Titres avec nom d'artiste**
|
||||
```sql
|
||||
SELECT T.nom AS titre, AR.nom AS artiste
|
||||
FROM TITRES T
|
||||
INNER JOIN ALBUMS AL ON T.id_album = AL.id
|
||||
INNER JOIN ARTISTES AR ON AL.id_artiste = AR.id;
|
||||
```
|
||||
|
||||
**9. Albums de Daft Punk**
|
||||
```sql
|
||||
SELECT AL.titre, AL.ann_sortie
|
||||
FROM ALBUMS AL
|
||||
INNER JOIN ARTISTES AR ON AL.id_artiste = AR.id
|
||||
WHERE AR.nom = 'Daft Punk';
|
||||
```
|
||||
Résultat : Random Access Memories (2013), Discovery (2001)
|
||||
|
||||
**10. Écoutes avec pseudo et titre**
|
||||
```sql
|
||||
SELECT U.pseudo, T.nom AS titre, E.date_ecoute
|
||||
FROM ECOUTES E
|
||||
INNER JOIN UTILISATEURS U ON E.id_utilisateur = U.id
|
||||
INNER JOIN TITRES T ON E.id_titre = T.id;
|
||||
```
|
||||
|
||||
**11. Titres des artistes français**
|
||||
```sql
|
||||
SELECT T.nom AS titre, AR.nom AS artiste
|
||||
FROM TITRES T
|
||||
INNER JOIN ALBUMS AL ON T.id_album = AL.id
|
||||
INNER JOIN ARTISTES AR ON AL.id_artiste = AR.id
|
||||
WHERE AR.pays = 'France';
|
||||
```
|
||||
|
||||
**12. Écoutes complètes**
|
||||
```sql
|
||||
SELECT U.pseudo, T.nom AS titre, AL.titre AS album, AR.nom AS artiste
|
||||
FROM ECOUTES E
|
||||
INNER JOIN UTILISATEURS U ON E.id_utilisateur = U.id
|
||||
INNER JOIN TITRES T ON E.id_titre = T.id
|
||||
INNER JOIN ALBUMS AL ON T.id_album = AL.id
|
||||
INNER JOIN ARTISTES AR ON AL.id_artiste = AR.id;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 4 : Agrégations
|
||||
|
||||
**13. Nombre de titres**
|
||||
```sql
|
||||
SELECT COUNT(*) AS nb_titres FROM TITRES;
|
||||
```
|
||||
Résultat : 43
|
||||
|
||||
**14. Durée moyenne des titres**
|
||||
```sql
|
||||
SELECT AVG(duree_sec) AS duree_moyenne FROM TITRES;
|
||||
```
|
||||
Résultat : environ 227 secondes
|
||||
|
||||
**15. Titre le plus long et le plus court**
|
||||
```sql
|
||||
-- Le plus long
|
||||
SELECT nom, duree_sec FROM TITRES WHERE duree_sec = (SELECT MAX(duree_sec) FROM TITRES);
|
||||
-- Résultat : Get Lucky (369 sec)
|
||||
|
||||
-- Le plus court
|
||||
SELECT nom, duree_sec FROM TITRES WHERE duree_sec = (SELECT MIN(duree_sec) FROM TITRES);
|
||||
-- Résultat : SMS (164 sec)
|
||||
```
|
||||
|
||||
**16. Nombre d'albums par artiste**
|
||||
```sql
|
||||
SELECT AR.nom, COUNT(*) AS nb_albums
|
||||
FROM ARTISTES AR
|
||||
INNER JOIN ALBUMS AL ON AR.id = AL.id_artiste
|
||||
GROUP BY AR.id
|
||||
ORDER BY nb_albums DESC;
|
||||
```
|
||||
|
||||
**17. Nombre d'écoutes par utilisateur**
|
||||
```sql
|
||||
SELECT U.pseudo, COUNT(*) AS nb_ecoutes
|
||||
FROM UTILISATEURS U
|
||||
INNER JOIN ECOUTES E ON U.id = E.id_utilisateur
|
||||
GROUP BY U.id
|
||||
ORDER BY nb_ecoutes DESC;
|
||||
```
|
||||
|
||||
**18. Nombre de titres par genre**
|
||||
```sql
|
||||
SELECT AR.genre_principal, COUNT(*) AS nb_titres
|
||||
FROM ARTISTES AR
|
||||
INNER JOIN ALBUMS AL ON AR.id = AL.id_artiste
|
||||
INNER JOIN TITRES T ON AL.id = T.id_album
|
||||
GROUP BY AR.genre_principal
|
||||
ORDER BY nb_titres DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 5 : Requêtes avancées
|
||||
|
||||
**19. Artistes avec plus d'un album**
|
||||
```sql
|
||||
SELECT AR.nom, COUNT(*) AS nb_albums
|
||||
FROM ARTISTES AR
|
||||
INNER JOIN ALBUMS AL ON AR.id = AL.id_artiste
|
||||
GROUP BY AR.id
|
||||
HAVING COUNT(*) > 1;
|
||||
```
|
||||
|
||||
**20. Top 5 des titres les plus écoutés**
|
||||
```sql
|
||||
SELECT T.nom, COUNT(*) AS nb_ecoutes
|
||||
FROM TITRES T
|
||||
INNER JOIN ECOUTES E ON T.id = E.id_titre
|
||||
GROUP BY T.id
|
||||
ORDER BY nb_ecoutes DESC
|
||||
LIMIT 5;
|
||||
```
|
||||
|
||||
**21. Utilisateurs ayant écouté Stromae**
|
||||
```sql
|
||||
SELECT DISTINCT U.pseudo
|
||||
FROM UTILISATEURS U
|
||||
INNER JOIN ECOUTES E ON U.id = E.id_utilisateur
|
||||
INNER JOIN TITRES T ON E.id_titre = T.id
|
||||
INNER JOIN ALBUMS AL ON T.id_album = AL.id
|
||||
INNER JOIN ARTISTES AR ON AL.id_artiste = AR.id
|
||||
WHERE AR.nom = 'Stromae';
|
||||
```
|
||||
|
||||
**22. Durée totale d'écoute par utilisateur (en minutes)**
|
||||
```sql
|
||||
SELECT U.pseudo, SUM(E.duree_ecoute_sec) / 60.0 AS duree_totale_min
|
||||
FROM UTILISATEURS U
|
||||
INNER JOIN ECOUTES E ON U.id = E.id_utilisateur
|
||||
GROUP BY U.id
|
||||
ORDER BY duree_totale_min DESC;
|
||||
```
|
||||
|
||||
**23. Artistes sans titres explicites**
|
||||
```sql
|
||||
SELECT DISTINCT AR.nom
|
||||
FROM ARTISTES AR
|
||||
WHERE AR.id NOT IN (
|
||||
SELECT DISTINCT AL.id_artiste
|
||||
FROM ALBUMS AL
|
||||
INNER JOIN TITRES T ON AL.id = T.id_album
|
||||
WHERE T.explicite = TRUE
|
||||
);
|
||||
```
|
||||
|
||||
**24. Écoutes par pays d'utilisateur**
|
||||
```sql
|
||||
SELECT U.pays, COUNT(*) AS nb_ecoutes, SUM(E.duree_ecoute_sec) / 60.0 AS duree_totale_min
|
||||
FROM UTILISATEURS U
|
||||
INNER JOIN ECOUTES E ON U.id = E.id_utilisateur
|
||||
GROUP BY U.pays
|
||||
ORDER BY nb_ecoutes DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 6 : Analyse business
|
||||
|
||||
**25. Taux de conversion**
|
||||
```sql
|
||||
SELECT type_abo, COUNT(*) AS nb_utilisateurs
|
||||
FROM UTILISATEURS
|
||||
GROUP BY type_abo;
|
||||
|
||||
-- Ou en pourcentage
|
||||
SELECT
|
||||
type_abo,
|
||||
COUNT(*) AS nb,
|
||||
ROUND(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM UTILISATEURS), 1) AS pourcentage
|
||||
FROM UTILISATEURS
|
||||
GROUP BY type_abo;
|
||||
```
|
||||
|
||||
**26. Artistes populaires auprès des Français**
|
||||
```sql
|
||||
SELECT AR.nom, COUNT(*) AS nb_ecoutes
|
||||
FROM ARTISTES AR
|
||||
INNER JOIN ALBUMS AL ON AR.id = AL.id_artiste
|
||||
INNER JOIN TITRES T ON AL.id = T.id_album
|
||||
INNER JOIN ECOUTES E ON T.id = E.id_titre
|
||||
INNER JOIN UTILISATEURS U ON E.id_utilisateur = U.id
|
||||
WHERE U.pays = 'France'
|
||||
GROUP BY AR.id
|
||||
ORDER BY nb_ecoutes DESC;
|
||||
```
|
||||
|
||||
**27. Utilisateurs Daft Punk mais pas Stromae**
|
||||
```sql
|
||||
SELECT DISTINCT U.pseudo
|
||||
FROM UTILISATEURS U
|
||||
INNER JOIN ECOUTES E ON U.id = E.id_utilisateur
|
||||
INNER JOIN TITRES T ON E.id_titre = T.id
|
||||
INNER JOIN ALBUMS AL ON T.id_album = AL.id
|
||||
INNER JOIN ARTISTES AR ON AL.id_artiste = AR.id
|
||||
WHERE AR.nom = 'Daft Punk'
|
||||
AND U.id NOT IN (
|
||||
SELECT DISTINCT U2.id
|
||||
FROM UTILISATEURS U2
|
||||
INNER JOIN ECOUTES E2 ON U2.id = E2.id_utilisateur
|
||||
INNER JOIN TITRES T2 ON E2.id_titre = T2.id
|
||||
INNER JOIN ALBUMS AL2 ON T2.id_album = AL2.id
|
||||
INNER JOIN ARTISTES AR2 ON AL2.id_artiste = AR2.id
|
||||
WHERE AR2.nom = 'Stromae'
|
||||
);
|
||||
```
|
||||
|
||||
**28. Pourcentage de contenu explicite**
|
||||
```sql
|
||||
SELECT
|
||||
ROUND(SUM(CASE WHEN explicite = TRUE THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS pct_explicite
|
||||
FROM TITRES;
|
||||
```
|
||||
|
||||
**29. Utilisateurs anciens actifs**
|
||||
```sql
|
||||
SELECT DISTINCT U.pseudo, U.date_inscription
|
||||
FROM UTILISATEURS U
|
||||
INNER JOIN ECOUTES E ON U.id = E.id_utilisateur
|
||||
WHERE U.date_inscription < '2021-01-01'
|
||||
AND E.date_ecoute BETWEEN '2024-01-01' AND '2024-01-31';
|
||||
```
|
||||
|
||||
**30. Vue synthétique par artiste**
|
||||
```sql
|
||||
SELECT
|
||||
AR.nom AS artiste,
|
||||
AR.pays,
|
||||
AR.genre_principal AS genre,
|
||||
COUNT(DISTINCT AL.id) AS nb_albums,
|
||||
COUNT(DISTINCT T.id) AS nb_titres,
|
||||
COUNT(E.id) AS nb_ecoutes
|
||||
FROM ARTISTES AR
|
||||
LEFT JOIN ALBUMS AL ON AR.id = AL.id_artiste
|
||||
LEFT JOIN TITRES T ON AL.id = T.id_album
|
||||
LEFT JOIN ECOUTES E ON T.id = E.id_titre
|
||||
GROUP BY AR.id
|
||||
ORDER BY nb_ecoutes DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 7 : Modifications de données
|
||||
|
||||
**31. Ajouter Angèle**
|
||||
```sql
|
||||
INSERT INTO ARTISTES (id, nom, pays, genre_principal, ann_debut)
|
||||
VALUES (11, 'Angèle', 'Belgique', 'Pop', 2014);
|
||||
```
|
||||
|
||||
**32. Ajouter l'album Brol**
|
||||
```sql
|
||||
INSERT INTO ALBUMS (id, titre, id_artiste, ann_sortie, nb_titres)
|
||||
VALUES (19, 'Brol', 11, 2018, 15);
|
||||
```
|
||||
|
||||
**33. Changer l'abonnement d'alex_beats**
|
||||
```sql
|
||||
UPDATE UTILISATEURS
|
||||
SET type_abo = 'etudiant'
|
||||
WHERE pseudo = 'alex_beats';
|
||||
```
|
||||
|
||||
**34. Supprimer les écoutes de jp_kpop**
|
||||
```sql
|
||||
DELETE FROM ECOUTES
|
||||
WHERE id_utilisateur = (SELECT id FROM UTILISATEURS WHERE pseudo = 'jp_kpop');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Questions de réflexion
|
||||
|
||||
**1. Pourquoi séparer artistes et albums ?**
|
||||
- Éviter la redondance : les infos de l'artiste ne sont stockées qu'une fois
|
||||
- Faciliter les mises à jour : changer le pays d'un artiste se fait en un seul endroit
|
||||
- Garantir la cohérence : pas de risque d'avoir "Daft Punk" et "DaftPunk"
|
||||
- C'est le principe de **normalisation** des bases de données
|
||||
|
||||
**2. Problème de suppression d'un artiste**
|
||||
- **Violation de contrainte d'intégrité référentielle** : les albums font référence à cet artiste via la clé étrangère
|
||||
- Solutions possibles :
|
||||
- Empêcher la suppression (comportement par défaut)
|
||||
- Supprimer en cascade tous les albums et titres associés (`ON DELETE CASCADE`)
|
||||
- Mettre la référence à NULL (`ON DELETE SET NULL`)
|
||||
|
||||
**3. Gérer les collaborations**
|
||||
- Créer une **table de liaison** COLLABORATIONS :
|
||||
```sql
|
||||
CREATE TABLE COLLABORATIONS (
|
||||
id_titre INTEGER,
|
||||
id_artiste INTEGER,
|
||||
role TEXT, -- 'principal', 'featuring', 'producteur'
|
||||
PRIMARY KEY (id_titre, id_artiste)
|
||||
);
|
||||
```
|
||||
- Ou modifier la table TITRES pour permettre plusieurs artistes
|
||||
|
||||
**4. Informations supplémentaires pour un vrai service**
|
||||
- **Playlists** : table PLAYLISTS avec les titres associés
|
||||
- **Historique complet** : horodatage précis des écoutes
|
||||
- **Préférences** : genres favoris, artistes suivis
|
||||
- **Social** : amis, partages, playlists collaboratives
|
||||
- **Paiements** : historique des abonnements, factures
|
||||
- **Métadonnées audio** : tempo, tonalité, énergie (pour les recommandations)
|
||||
- **Paroles** : table LYRICS liée aux titres
|
||||
- **Podcasts** : extension du modèle pour d'autres types de contenu
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
554
SQL/Cours_SQL.md
Normal file
554
SQL/Cours_SQL.md
Normal file
@@ -0,0 +1,554 @@
|
||||
# Cours : Le langage SQL
|
||||
|
||||
---
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
### 1.1. Historique
|
||||
|
||||
**SQL** (*Structured Query Language*) est un langage de requêtes créé en 1974 par IBM, puis normalisé en 1986. Il permet d'interagir avec les **bases de données relationnelles**.
|
||||
|
||||
SQL est aujourd'hui le standard universel pour :
|
||||
- Créer et modifier la structure des bases de données
|
||||
- Insérer, modifier et supprimer des données
|
||||
- Interroger les données (requêtes)
|
||||
|
||||
### 1.2. Les SGBD
|
||||
|
||||
Un **SGBD** (*Système de Gestion de Base de Données*) est un logiciel qui permet de stocker, organiser et manipuler des données. Exemples :
|
||||
|
||||
| SGBD | Type | Utilisation |
|
||||
|------|------|-------------|
|
||||
| SQLite | Léger, fichier local | Applications mobiles, embarqué |
|
||||
| MySQL / MariaDB | Serveur | Sites web, applications |
|
||||
| PostgreSQL | Serveur avancé | Applications complexes |
|
||||
| Oracle | Entreprise | Grandes entreprises |
|
||||
| Microsoft SQL Server | Entreprise | Environnement Windows |
|
||||
|
||||
En NSI, nous utilisons principalement **SQLite** avec l'outil **DB Browser for SQLite**.
|
||||
|
||||
---
|
||||
|
||||
## 2. Structure d'une base de données
|
||||
|
||||
### 2.1. Tables, attributs et enregistrements
|
||||
|
||||
Une base de données relationnelle est composée de **tables**. Chaque table contient :
|
||||
- Des **colonnes** (ou **attributs**) : les caractéristiques des données
|
||||
- Des **lignes** (ou **enregistrements**) : les données elles-mêmes
|
||||
|
||||
**Exemple : Table LIVRES**
|
||||
|
||||
| id | titre | auteur | ann_publi | note |
|
||||
|----|-------|--------|-----------|------|
|
||||
| 1 | 1984 | Orwell | 1949 | 10 |
|
||||
| 2 | Dune | Herbert | 1965 | 8 |
|
||||
| 3 | Fondation | Asimov | 1951 | 9 |
|
||||
|
||||
### 2.2. Types de données
|
||||
|
||||
| Type SQL | Description | Exemple |
|
||||
|----------|-------------|---------|
|
||||
| `INT` ou `INTEGER` | Nombre entier | 42, -7, 2024 |
|
||||
| `REAL` ou `FLOAT` | Nombre décimal | 3.14, -0.5 |
|
||||
| `TEXT` ou `VARCHAR` | Chaîne de caractères | 'Bonjour', 'Alice' |
|
||||
| `DATE` | Date | '2024-01-15' |
|
||||
| `BOOLEAN` | Booléen | TRUE, FALSE |
|
||||
|
||||
### 2.3. Clés primaires et étrangères
|
||||
|
||||
- **Clé primaire** (`PRIMARY KEY`) : Identifiant unique de chaque enregistrement
|
||||
- **Clé étrangère** (`FOREIGN KEY`) : Référence vers la clé primaire d'une autre table
|
||||
|
||||
```
|
||||
Table AUTEURS Table LIVRES
|
||||
+----+--------+ +----+--------+-----------+
|
||||
| id | nom | | id | titre | id_auteur |
|
||||
+----+--------+ +----+--------+-----------+
|
||||
| 1 | Orwell |<─────────────────| 1 | 1984 | 1 |
|
||||
| 2 | Asimov |<─────────────────| 2 | Robots | 2 |
|
||||
+----+--------+ +----+--------+-----------+
|
||||
PK PK FK
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Création et modification de tables
|
||||
|
||||
### 3.1. Créer une table : CREATE TABLE
|
||||
|
||||
```sql
|
||||
CREATE TABLE LIVRES (
|
||||
id INTEGER PRIMARY KEY,
|
||||
titre TEXT,
|
||||
auteur TEXT,
|
||||
ann_publi INTEGER,
|
||||
note INTEGER
|
||||
);
|
||||
```
|
||||
|
||||
### 3.2. Créer une table avec clé étrangère
|
||||
|
||||
```sql
|
||||
CREATE TABLE LIVRES (
|
||||
id INTEGER PRIMARY KEY,
|
||||
titre TEXT,
|
||||
id_auteur INTEGER,
|
||||
ann_publi INTEGER,
|
||||
FOREIGN KEY (id_auteur) REFERENCES AUTEURS(id)
|
||||
);
|
||||
```
|
||||
|
||||
### 3.3. Supprimer une table : DROP TABLE
|
||||
|
||||
```sql
|
||||
DROP TABLE LIVRES;
|
||||
```
|
||||
|
||||
⚠️ **Attention** : Cette opération est irréversible !
|
||||
|
||||
### 3.4. Modifier une table : ALTER TABLE
|
||||
|
||||
```sql
|
||||
-- Ajouter une colonne
|
||||
ALTER TABLE LIVRES ADD COLUMN editeur TEXT;
|
||||
|
||||
-- Supprimer une colonne (selon le SGBD)
|
||||
ALTER TABLE LIVRES DROP COLUMN editeur;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Manipulation des données
|
||||
|
||||
### 4.1. Insérer des données : INSERT INTO
|
||||
|
||||
```sql
|
||||
-- Insérer un enregistrement
|
||||
INSERT INTO LIVRES (id, titre, auteur, ann_publi, note)
|
||||
VALUES (1, '1984', 'Orwell', 1949, 10);
|
||||
|
||||
-- Insérer plusieurs enregistrements
|
||||
INSERT INTO LIVRES (id, titre, auteur, ann_publi, note)
|
||||
VALUES
|
||||
(2, 'Dune', 'Herbert', 1965, 8),
|
||||
(3, 'Fondation', 'Asimov', 1951, 9);
|
||||
```
|
||||
|
||||
### 4.2. Modifier des données : UPDATE
|
||||
|
||||
```sql
|
||||
-- Modifier tous les enregistrements correspondant à la condition
|
||||
UPDATE LIVRES
|
||||
SET note = 10
|
||||
WHERE auteur = 'Asimov';
|
||||
|
||||
-- Modifier plusieurs colonnes
|
||||
UPDATE LIVRES
|
||||
SET note = 9, ann_publi = 1950
|
||||
WHERE id = 3;
|
||||
```
|
||||
|
||||
⚠️ **Attention** : Sans clause `WHERE`, tous les enregistrements seront modifiés !
|
||||
|
||||
### 4.3. Supprimer des données : DELETE
|
||||
|
||||
```sql
|
||||
-- Supprimer les enregistrements correspondant à la condition
|
||||
DELETE FROM LIVRES
|
||||
WHERE ann_publi < 1950;
|
||||
|
||||
-- Supprimer tous les enregistrements (vider la table)
|
||||
DELETE FROM LIVRES;
|
||||
```
|
||||
|
||||
⚠️ **Attention** : Sans clause `WHERE`, tous les enregistrements seront supprimés !
|
||||
|
||||
---
|
||||
|
||||
## 5. Requêtes de sélection : SELECT
|
||||
|
||||
### 5.1. Syntaxe de base
|
||||
|
||||
```sql
|
||||
SELECT colonnes
|
||||
FROM table
|
||||
WHERE conditions
|
||||
ORDER BY colonne [ASC|DESC];
|
||||
```
|
||||
|
||||
### 5.2. Sélectionner des colonnes
|
||||
|
||||
```sql
|
||||
-- Toutes les colonnes
|
||||
SELECT * FROM LIVRES;
|
||||
|
||||
-- Colonnes spécifiques
|
||||
SELECT titre, auteur FROM LIVRES;
|
||||
|
||||
-- Avec alias
|
||||
SELECT titre AS "Titre du livre", auteur AS "Écrivain"
|
||||
FROM LIVRES;
|
||||
```
|
||||
|
||||
### 5.3. Filtrer avec WHERE
|
||||
|
||||
**Opérateurs de comparaison :**
|
||||
|
||||
| Opérateur | Signification |
|
||||
|-----------|---------------|
|
||||
| `=` | Égal à |
|
||||
| `<>` ou `!=` | Différent de |
|
||||
| `<`, `<=` | Inférieur (ou égal) |
|
||||
| `>`, `>=` | Supérieur (ou égal) |
|
||||
| `BETWEEN a AND b` | Entre a et b (inclus) |
|
||||
| `IN (v1, v2, ...)` | Dans la liste |
|
||||
| `LIKE` | Correspondance de motif |
|
||||
| `IS NULL` | Est nul |
|
||||
|
||||
**Exemples :**
|
||||
|
||||
```sql
|
||||
-- Égalité
|
||||
SELECT * FROM LIVRES WHERE auteur = 'Asimov';
|
||||
|
||||
-- Comparaison
|
||||
SELECT * FROM LIVRES WHERE ann_publi > 1960;
|
||||
|
||||
-- Entre deux valeurs
|
||||
SELECT * FROM LIVRES WHERE ann_publi BETWEEN 1950 AND 1970;
|
||||
|
||||
-- Dans une liste
|
||||
SELECT * FROM LIVRES WHERE auteur IN ('Asimov', 'Bradbury', 'K.Dick');
|
||||
|
||||
-- Correspondance de motif (LIKE)
|
||||
SELECT * FROM LIVRES WHERE titre LIKE '%Robot%';
|
||||
-- % = n'importe quelle suite de caractères
|
||||
-- _ = un seul caractère
|
||||
|
||||
-- Valeur nulle
|
||||
SELECT * FROM LIVRES WHERE note IS NULL;
|
||||
```
|
||||
|
||||
### 5.4. Combiner les conditions : AND, OR, NOT
|
||||
|
||||
```sql
|
||||
-- ET logique
|
||||
SELECT * FROM LIVRES
|
||||
WHERE auteur = 'Asimov' AND ann_publi > 1950;
|
||||
|
||||
-- OU logique
|
||||
SELECT * FROM LIVRES
|
||||
WHERE auteur = 'Asimov' OR auteur = 'Bradbury';
|
||||
|
||||
-- Négation
|
||||
SELECT * FROM LIVRES
|
||||
WHERE NOT auteur = 'Asimov';
|
||||
|
||||
-- Combinaison avec parenthèses
|
||||
SELECT * FROM LIVRES
|
||||
WHERE (auteur = 'Asimov' OR auteur = 'Bradbury') AND note >= 8;
|
||||
```
|
||||
|
||||
### 5.5. Trier les résultats : ORDER BY
|
||||
|
||||
```sql
|
||||
-- Tri croissant (par défaut)
|
||||
SELECT * FROM LIVRES ORDER BY ann_publi;
|
||||
SELECT * FROM LIVRES ORDER BY ann_publi ASC;
|
||||
|
||||
-- Tri décroissant
|
||||
SELECT * FROM LIVRES ORDER BY note DESC;
|
||||
|
||||
-- Tri multiple
|
||||
SELECT * FROM LIVRES ORDER BY auteur ASC, ann_publi DESC;
|
||||
```
|
||||
|
||||
### 5.6. Éliminer les doublons : DISTINCT
|
||||
|
||||
```sql
|
||||
-- Liste des auteurs (sans doublons)
|
||||
SELECT DISTINCT auteur FROM LIVRES;
|
||||
```
|
||||
|
||||
### 5.7. Limiter les résultats : LIMIT
|
||||
|
||||
```sql
|
||||
-- Les 5 premiers résultats
|
||||
SELECT * FROM LIVRES LIMIT 5;
|
||||
|
||||
-- Pagination : 5 résultats à partir du 10e
|
||||
SELECT * FROM LIVRES LIMIT 5 OFFSET 10;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Fonctions d'agrégation
|
||||
|
||||
Les fonctions d'agrégation effectuent des calculs sur un ensemble de valeurs.
|
||||
|
||||
### 6.1. Les fonctions principales
|
||||
|
||||
| Fonction | Description |
|
||||
|----------|-------------|
|
||||
| `COUNT(*)` | Nombre d'enregistrements |
|
||||
| `COUNT(colonne)` | Nombre de valeurs non nulles |
|
||||
| `SUM(colonne)` | Somme des valeurs |
|
||||
| `AVG(colonne)` | Moyenne des valeurs |
|
||||
| `MIN(colonne)` | Valeur minimale |
|
||||
| `MAX(colonne)` | Valeur maximale |
|
||||
|
||||
### 6.2. Exemples
|
||||
|
||||
```sql
|
||||
-- Nombre total de livres
|
||||
SELECT COUNT(*) FROM LIVRES;
|
||||
|
||||
-- Nombre de livres par auteur
|
||||
SELECT COUNT(*) FROM LIVRES WHERE auteur = 'Asimov';
|
||||
|
||||
-- Note moyenne
|
||||
SELECT AVG(note) FROM LIVRES;
|
||||
|
||||
-- Note minimale et maximale
|
||||
SELECT MIN(note), MAX(note) FROM LIVRES;
|
||||
|
||||
-- Somme des notes (peu utile ici, mais illustratif)
|
||||
SELECT SUM(note) FROM LIVRES;
|
||||
|
||||
-- Année du livre le plus ancien
|
||||
SELECT MIN(ann_publi) FROM LIVRES;
|
||||
```
|
||||
|
||||
### 6.3. Regrouper les données : GROUP BY
|
||||
|
||||
`GROUP BY` permet de regrouper les enregistrements par valeur d'une colonne.
|
||||
|
||||
```sql
|
||||
-- Nombre de livres par auteur
|
||||
SELECT auteur, COUNT(*) AS nb_livres
|
||||
FROM LIVRES
|
||||
GROUP BY auteur;
|
||||
|
||||
-- Note moyenne par auteur
|
||||
SELECT auteur, AVG(note) AS note_moyenne
|
||||
FROM LIVRES
|
||||
GROUP BY auteur;
|
||||
|
||||
-- Résultat :
|
||||
-- +----------+--------------+
|
||||
-- | auteur | note_moyenne |
|
||||
-- +----------+--------------+
|
||||
-- | Asimov | 8.67 |
|
||||
-- | Bradbury | 7.50 |
|
||||
-- | K.Dick | 8.33 |
|
||||
-- +----------+--------------+
|
||||
```
|
||||
|
||||
### 6.4. Filtrer les groupes : HAVING
|
||||
|
||||
`HAVING` filtre les résultats **après** le regroupement (contrairement à `WHERE` qui filtre **avant**).
|
||||
|
||||
```sql
|
||||
-- Auteurs ayant écrit plus de 2 livres
|
||||
SELECT auteur, COUNT(*) AS nb_livres
|
||||
FROM LIVRES
|
||||
GROUP BY auteur
|
||||
HAVING COUNT(*) > 2;
|
||||
|
||||
-- Auteurs avec une note moyenne >= 8
|
||||
SELECT auteur, AVG(note) AS note_moyenne
|
||||
FROM LIVRES
|
||||
GROUP BY auteur
|
||||
HAVING AVG(note) >= 8;
|
||||
```
|
||||
|
||||
**Différence WHERE / HAVING :**
|
||||
|
||||
```sql
|
||||
-- WHERE filtre les lignes AVANT le regroupement
|
||||
SELECT auteur, AVG(note)
|
||||
FROM LIVRES
|
||||
WHERE ann_publi > 1950 -- Filtre les livres publiés après 1950
|
||||
GROUP BY auteur;
|
||||
|
||||
-- HAVING filtre les groupes APRÈS le regroupement
|
||||
SELECT auteur, AVG(note)
|
||||
FROM LIVRES
|
||||
GROUP BY auteur
|
||||
HAVING AVG(note) > 8; -- Garde les auteurs avec moyenne > 8
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Jointures
|
||||
|
||||
Les jointures permettent de combiner des données provenant de plusieurs tables.
|
||||
|
||||
### 7.1. INNER JOIN (jointure interne)
|
||||
|
||||
Retourne uniquement les enregistrements qui ont une correspondance dans les deux tables.
|
||||
|
||||
```sql
|
||||
SELECT LIVRES.titre, AUTEURS.nom, AUTEURS.prenom
|
||||
FROM LIVRES
|
||||
INNER JOIN AUTEURS ON LIVRES.id_auteur = AUTEURS.id;
|
||||
```
|
||||
|
||||
**Schéma :**
|
||||
```
|
||||
LIVRES AUTEURS Résultat INNER JOIN
|
||||
+----+------+ +----+------+ +------+------+
|
||||
| id | id_a | | id | nom | | titre| nom |
|
||||
+----+------+ +----+------+ +------+------+
|
||||
| 1 | 1 | | 1 | Orwell| | 1984 | Orwell|
|
||||
| 2 | 2 | | 2 | Asimov| | Fond.| Asimov|
|
||||
| 3 | NULL | | 3 | Dick | +------+------+
|
||||
+----+------+ +----+------+ (le livre 3 est exclu car id_a est NULL)
|
||||
```
|
||||
|
||||
### 7.2. LEFT JOIN (jointure externe gauche)
|
||||
|
||||
Retourne tous les enregistrements de la table de gauche, même sans correspondance.
|
||||
|
||||
```sql
|
||||
SELECT LIVRES.titre, AUTEURS.nom
|
||||
FROM LIVRES
|
||||
LEFT JOIN AUTEURS ON LIVRES.id_auteur = AUTEURS.id;
|
||||
```
|
||||
|
||||
### 7.3. Alias de tables
|
||||
|
||||
Pour simplifier l'écriture :
|
||||
|
||||
```sql
|
||||
SELECT L.titre, A.nom, A.prenom
|
||||
FROM LIVRES L
|
||||
INNER JOIN AUTEURS A ON L.id_auteur = A.id
|
||||
WHERE A.langue_ecriture = 'français';
|
||||
```
|
||||
|
||||
### 7.4. Jointures multiples
|
||||
|
||||
```sql
|
||||
SELECT L.titre, A.nom, E.nom_editeur
|
||||
FROM LIVRES L
|
||||
INNER JOIN AUTEURS A ON L.id_auteur = A.id
|
||||
INNER JOIN EDITEURS E ON L.id_editeur = E.id;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Ordre d'exécution des clauses
|
||||
|
||||
L'ordre d'écriture et l'ordre d'exécution sont différents :
|
||||
|
||||
**Ordre d'écriture :**
|
||||
```sql
|
||||
SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT ...
|
||||
```
|
||||
|
||||
**Ordre d'exécution :**
|
||||
1. `FROM` et `JOIN` : Sélection des tables
|
||||
2. `WHERE` : Filtrage des lignes
|
||||
3. `GROUP BY` : Regroupement
|
||||
4. `HAVING` : Filtrage des groupes
|
||||
5. `SELECT` : Sélection des colonnes
|
||||
6. `DISTINCT` : Élimination des doublons
|
||||
7. `ORDER BY` : Tri
|
||||
8. `LIMIT` : Limitation du nombre de résultats
|
||||
|
||||
---
|
||||
|
||||
## 9. Bonnes pratiques
|
||||
|
||||
### 9.1. Conventions d'écriture
|
||||
|
||||
- Mots-clés SQL en **MAJUSCULES** : `SELECT`, `FROM`, `WHERE`
|
||||
- Noms de tables en **MAJUSCULES** : `LIVRES`, `AUTEURS`
|
||||
- Noms de colonnes en **minuscules** : `titre`, `auteur`
|
||||
- Indentation pour la lisibilité
|
||||
|
||||
```sql
|
||||
SELECT L.titre,
|
||||
A.nom,
|
||||
A.prenom
|
||||
FROM LIVRES L
|
||||
INNER JOIN AUTEURS A ON L.id_auteur = A.id
|
||||
WHERE A.langue_ecriture = 'français'
|
||||
AND L.ann_publi > 1950
|
||||
ORDER BY L.ann_publi DESC;
|
||||
```
|
||||
|
||||
### 9.2. Sécurité : Injections SQL
|
||||
|
||||
⚠️ Ne jamais construire des requêtes SQL par concaténation de chaînes avec des entrées utilisateur !
|
||||
|
||||
```python
|
||||
# DANGEREUX - Injection SQL possible
|
||||
requete = "SELECT * FROM USERS WHERE nom = '" + nom_utilisateur + "'"
|
||||
|
||||
# SÉCURISÉ - Requête paramétrée
|
||||
cursor.execute("SELECT * FROM USERS WHERE nom = ?", (nom_utilisateur,))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Synthèse
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ REQUÊTE SQL │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ SELECT [DISTINCT] colonnes, AGG(colonne) │
|
||||
│ FROM table1 │
|
||||
│ [INNER|LEFT] JOIN table2 ON condition │
|
||||
│ WHERE conditions │
|
||||
│ GROUP BY colonne │
|
||||
│ HAVING condition_agregation │
|
||||
│ ORDER BY colonne [ASC|DESC] │
|
||||
│ LIMIT n [OFFSET m] │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌──────────────┬────────────────────────────────────────────────┐
|
||||
│ Commande │ Action │
|
||||
├──────────────┼────────────────────────────────────────────────┤
|
||||
│ CREATE TABLE │ Créer une table │
|
||||
│ DROP TABLE │ Supprimer une table │
|
||||
│ INSERT INTO │ Insérer des données │
|
||||
│ UPDATE │ Modifier des données │
|
||||
│ DELETE │ Supprimer des données │
|
||||
│ SELECT │ Interroger des données │
|
||||
└──────────────┴────────────────────────────────────────────────┘
|
||||
|
||||
┌──────────────┬────────────────────────────────────────────────┐
|
||||
│ Agrégation │ Description │
|
||||
├──────────────┼────────────────────────────────────────────────┤
|
||||
│ COUNT(*) │ Nombre d'enregistrements │
|
||||
│ SUM(col) │ Somme │
|
||||
│ AVG(col) │ Moyenne │
|
||||
│ MIN(col) │ Minimum │
|
||||
│ MAX(col) │ Maximum │
|
||||
└──────────────┴────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pour aller plus loin
|
||||
|
||||
- **SQL Murder Mystery** : Un jeu pour apprendre SQL en résolvant un meurtre
|
||||
[https://mystery.knightlab.com](https://mystery.knightlab.com)
|
||||
|
||||
- **SQLBolt** : Tutoriel interactif
|
||||
[https://sqlbolt.com](https://sqlbolt.com)
|
||||
|
||||
- **W3Schools SQL** : Référence complète
|
||||
[https://www.w3schools.com/sql/](https://www.w3schools.com/sql/)
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
279
SQL/EXERCICES.md
Normal file
279
SQL/EXERCICES.md
Normal file
@@ -0,0 +1,279 @@
|
||||
# Exercices — SQL
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Pour tous les exercices, on considère la base de données d'une médiathèque contenant les tables suivantes :
|
||||
|
||||
**Table AUTEURS :**
|
||||
|
||||
| id | nom | prenom | nationalite | ann_naissance |
|
||||
|----|-----|--------|-------------|---------------|
|
||||
| 1 | Orwell | George | britannique | 1903 |
|
||||
| 2 | Herbert | Frank | américain | 1920 |
|
||||
| 3 | Asimov | Isaac | américain | 1920 |
|
||||
| 4 | Huxley | Aldous | britannique | 1894 |
|
||||
| 5 | Bradbury | Ray | américain | 1920 |
|
||||
| 6 | Dick | Philip K. | américain | 1928 |
|
||||
| 7 | Barjavel | René | français | 1911 |
|
||||
| 8 | Verne | Jules | français | 1828 |
|
||||
|
||||
**Table LIVRES :**
|
||||
|
||||
| id | titre | id_auteur | ann_publi | genre | nb_pages |
|
||||
|----|-------|-----------|-----------|-------|----------|
|
||||
| 1 | 1984 | 1 | 1949 | dystopie | 328 |
|
||||
| 2 | Dune | 2 | 1965 | space opera | 896 |
|
||||
| 3 | Fondation | 3 | 1951 | space opera | 256 |
|
||||
| 4 | Le meilleur des mondes | 4 | 1931 | dystopie | 288 |
|
||||
| 5 | Fahrenheit 451 | 5 | 1953 | dystopie | 192 |
|
||||
| 6 | Ubik | 6 | 1969 | SF | 224 |
|
||||
| 7 | Chroniques martiennes | 5 | 1950 | SF | 256 |
|
||||
| 8 | La nuit des temps | 7 | 1968 | SF | 318 |
|
||||
| 9 | Les Robots | 3 | 1950 | SF | 253 |
|
||||
| 10 | Ravage | 7 | 1943 | post-apo | 316 |
|
||||
| 11 | De la Terre à la Lune | 8 | 1865 | aventure | 192 |
|
||||
| 12 | Vingt mille lieues sous les mers | 8 | 1870 | aventure | 480 |
|
||||
|
||||
**Table EMPRUNTS :**
|
||||
|
||||
| id | id_livre | id_adherent | date_emprunt | date_retour |
|
||||
|----|----------|-------------|--------------|-------------|
|
||||
| 1 | 1 | 101 | 2024-01-15 | 2024-01-29 |
|
||||
| 2 | 3 | 102 | 2024-01-20 | NULL |
|
||||
| 3 | 5 | 101 | 2024-02-01 | 2024-02-10 |
|
||||
| 4 | 2 | 103 | 2024-02-05 | NULL |
|
||||
| 5 | 1 | 104 | 2024-02-10 | 2024-02-20 |
|
||||
|
||||
---
|
||||
|
||||
## Exercice 1 : Requêtes SELECT simples
|
||||
|
||||
Écrire les requêtes SQL permettant d'obtenir :
|
||||
|
||||
1. Tous les livres de la table LIVRES.
|
||||
|
||||
2. Les titres et années de publication de tous les livres.
|
||||
|
||||
3. Les noms et prénoms de tous les auteurs.
|
||||
|
||||
4. Les titres des livres publiés après 1950.
|
||||
|
||||
5. Les titres des livres du genre "dystopie".
|
||||
|
||||
6. Les auteurs de nationalité française.
|
||||
|
||||
---
|
||||
|
||||
## Exercice 2 : Filtres et conditions
|
||||
|
||||
Écrire les requêtes SQL permettant d'obtenir :
|
||||
|
||||
1. Les livres publiés entre 1940 et 1960 (inclus).
|
||||
|
||||
2. Les livres ayant plus de 300 pages.
|
||||
|
||||
3. Les auteurs nés après 1900 et de nationalité américaine.
|
||||
|
||||
4. Les livres dont le titre contient le mot "Terre".
|
||||
|
||||
5. Les livres qui ne sont pas du genre "SF".
|
||||
|
||||
6. Les auteurs dont le prénom commence par la lettre "R".
|
||||
|
||||
---
|
||||
|
||||
## Exercice 3 : Tri et limitation
|
||||
|
||||
Écrire les requêtes SQL permettant d'obtenir :
|
||||
|
||||
1. Tous les livres triés par année de publication (du plus ancien au plus récent).
|
||||
|
||||
2. Les 5 livres les plus récents.
|
||||
|
||||
3. Les auteurs triés par année de naissance décroissante.
|
||||
|
||||
4. Les 3 livres ayant le plus de pages.
|
||||
|
||||
5. Les livres triés par genre, puis par titre alphabétique.
|
||||
|
||||
6. La liste des genres sans doublons.
|
||||
|
||||
---
|
||||
|
||||
## Exercice 4 : Fonctions d'agrégation
|
||||
|
||||
Écrire les requêtes SQL permettant d'obtenir :
|
||||
|
||||
1. Le nombre total de livres dans la base.
|
||||
|
||||
2. Le nombre de pages du livre le plus long.
|
||||
|
||||
3. L'année de publication du livre le plus ancien.
|
||||
|
||||
4. Le nombre moyen de pages des livres.
|
||||
|
||||
5. Le nombre de livres par genre.
|
||||
|
||||
6. Le nombre total de pages de tous les livres de Jules Verne (id_auteur = 8).
|
||||
|
||||
---
|
||||
|
||||
## Exercice 5 : GROUP BY et HAVING
|
||||
|
||||
Écrire les requêtes SQL permettant d'obtenir :
|
||||
|
||||
1. Le nombre de livres écrits par chaque auteur (afficher id_auteur et le compte).
|
||||
|
||||
2. Le nombre moyen de pages par genre.
|
||||
|
||||
3. Les genres ayant plus de 2 livres.
|
||||
|
||||
4. Les auteurs ayant écrit au moins 2 livres (afficher id_auteur et le nombre).
|
||||
|
||||
5. L'année de publication du premier livre de chaque auteur.
|
||||
|
||||
6. Les genres dont la moyenne de pages dépasse 250.
|
||||
|
||||
---
|
||||
|
||||
## Exercice 6 : Jointures
|
||||
|
||||
Écrire les requêtes SQL permettant d'obtenir :
|
||||
|
||||
1. Les titres des livres avec le nom et prénom de leur auteur.
|
||||
|
||||
2. Les titres des livres écrits par des auteurs français.
|
||||
|
||||
3. Les titres et auteurs des livres du genre "dystopie", triés par année.
|
||||
|
||||
4. Le nom des auteurs ayant écrit des livres de plus de 400 pages.
|
||||
|
||||
5. Les livres (titre) avec le nom de l'auteur, uniquement pour les auteurs américains nés après 1910.
|
||||
|
||||
6. Pour chaque nationalité, le nombre de livres écrits par des auteurs de cette nationalité.
|
||||
|
||||
---
|
||||
|
||||
## Exercice 7 : Requêtes complexes
|
||||
|
||||
Écrire les requêtes SQL permettant d'obtenir :
|
||||
|
||||
1. Le titre du livre le plus long de chaque auteur, avec le nom de l'auteur.
|
||||
|
||||
2. Les auteurs n'ayant écrit qu'un seul livre (afficher nom, prénom, titre du livre).
|
||||
|
||||
3. Le nombre moyen de pages des livres par nationalité d'auteur.
|
||||
|
||||
4. Les genres pour lesquels tous les livres ont été publiés après 1940.
|
||||
|
||||
5. Le nom complet (prénom + nom) des auteurs et le nombre total de pages qu'ils ont écrites.
|
||||
|
||||
---
|
||||
|
||||
## Exercice 8 : INSERT, UPDATE, DELETE
|
||||
|
||||
1. Écrire une requête pour ajouter l'auteur suivant :
|
||||
- id : 9
|
||||
- nom : "Le Guin"
|
||||
- prénom : "Ursula K."
|
||||
- nationalité : "américain"
|
||||
- année de naissance : 1929
|
||||
|
||||
2. Écrire une requête pour ajouter le livre suivant :
|
||||
- id : 13
|
||||
- titre : "La Main gauche de la nuit"
|
||||
- id_auteur : 9
|
||||
- année de publication : 1969
|
||||
- genre : "SF"
|
||||
- nombre de pages : 304
|
||||
|
||||
3. Écrire une requête pour changer le genre de "Dune" en "SF".
|
||||
|
||||
4. Écrire une requête pour augmenter de 10% le nombre de pages de tous les livres de Jules Verne.
|
||||
|
||||
5. Écrire une requête pour supprimer tous les livres publiés avant 1900.
|
||||
|
||||
---
|
||||
|
||||
## Exercice 9 : Création de tables
|
||||
|
||||
1. Écrire la requête SQL pour créer la table EMPRUNTS avec :
|
||||
- id (entier, clé primaire)
|
||||
- id_livre (entier, clé étrangère vers LIVRES)
|
||||
- id_adherent (entier)
|
||||
- date_emprunt (date)
|
||||
- date_retour (date, peut être NULL)
|
||||
|
||||
2. Écrire la requête SQL pour créer une table EDITEURS avec :
|
||||
- id (entier, clé primaire)
|
||||
- nom (texte)
|
||||
- pays (texte)
|
||||
- ann_creation (entier)
|
||||
|
||||
3. Comment modifier la table LIVRES pour ajouter une colonne id_editeur qui référence la table EDITEURS ?
|
||||
|
||||
---
|
||||
|
||||
## Exercice 10 : Analyse de requêtes
|
||||
|
||||
Pour chaque requête suivante, décrire en français ce qu'elle retourne :
|
||||
|
||||
1. ```sql
|
||||
SELECT titre FROM LIVRES WHERE ann_publi = (SELECT MIN(ann_publi) FROM LIVRES);
|
||||
```
|
||||
|
||||
2. ```sql
|
||||
SELECT A.nom, COUNT(*)
|
||||
FROM AUTEURS A
|
||||
INNER JOIN LIVRES L ON A.id = L.id_auteur
|
||||
GROUP BY A.id
|
||||
HAVING COUNT(*) = (SELECT MAX(cnt) FROM (SELECT COUNT(*) as cnt FROM LIVRES GROUP BY id_auteur));
|
||||
```
|
||||
|
||||
3. ```sql
|
||||
SELECT DISTINCT genre FROM LIVRES WHERE genre NOT IN (SELECT genre FROM LIVRES WHERE ann_publi < 1950);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exercice 11 : QCM
|
||||
|
||||
1. Quelle clause permet de filtrer les résultats d'un GROUP BY ?
|
||||
- [ ] a) WHERE
|
||||
- [ ] b) FILTER
|
||||
- [ ] c) HAVING
|
||||
- [ ] d) GROUP FILTER
|
||||
|
||||
2. Quelle est la différence entre WHERE et HAVING ?
|
||||
- [ ] a) Aucune, ils sont équivalents
|
||||
- [ ] b) WHERE filtre avant GROUP BY, HAVING filtre après
|
||||
- [ ] c) HAVING filtre avant GROUP BY, WHERE filtre après
|
||||
- [ ] d) WHERE ne fonctionne qu'avec les nombres
|
||||
|
||||
3. Que retourne `SELECT COUNT(*) FROM LIVRES WHERE 1=0;` ?
|
||||
- [ ] a) Une erreur
|
||||
- [ ] b) NULL
|
||||
- [ ] c) 0
|
||||
- [ ] d) Rien
|
||||
|
||||
4. Quel type de jointure retourne tous les enregistrements de la table de gauche ?
|
||||
- [ ] a) INNER JOIN
|
||||
- [ ] b) LEFT JOIN
|
||||
- [ ] c) RIGHT JOIN
|
||||
- [ ] d) CROSS JOIN
|
||||
|
||||
5. Quelle fonction d'agrégation ignore les valeurs NULL ?
|
||||
- [ ] a) COUNT(*)
|
||||
- [ ] b) COUNT(colonne)
|
||||
- [ ] c) Les deux
|
||||
- [ ] d) Aucune
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
Ce TP vous guidera à travers la création et la manipulation d'une base de données en utilisant le logiciel **DB Browser for SQLite**. Vous apprendrez à créer des tables, insérer des données et exécuter des requêtes SQL pour interroger la base de données.
|
||||
|
||||
> **Prérequis** : Avoir lu le cours [Cours_SQL.md](Cours_SQL.md) avant de commencer ce TP.
|
||||
|
||||
## Prérequis
|
||||
|
||||
- Télécharger et installer [DB Browser for SQLite](https://sqlitebrowser.org/).
|
||||
@@ -46,7 +48,7 @@ Ce TP vous guidera à travers la création et la manipulation d'une base de donn
|
||||
);
|
||||
```
|
||||
|
||||
- Cliquez sur le triangle vert (ou appuyez sur F5) pour exécuter la requête.
|
||||
- Cliquez sur le bouton ▶ (ou appuyez sur F5) pour exécuter la requête.
|
||||
- Un message "Requête exécutée avec succès" devrait apparaître.
|
||||
|
||||

|
||||
@@ -77,7 +79,7 @@ Ce TP vous guidera à travers la création et la manipulation d'une base de donn
|
||||
(16, 'De la Terre à la Lune', 'Verne', 1865, 10);
|
||||
```
|
||||
|
||||
- Exécutez la requête en cliquant sur le triangle bleu ou en appuyant sur F5.
|
||||
- Exécutez la requête en cliquant sur le bouton ▶ ou en appuyant sur F5.
|
||||
- Un message de confirmation devrait apparaître.
|
||||
|
||||

|
||||
@@ -140,7 +142,7 @@ Ce TP vous guidera à travers la création et la manipulation d'une base de donn
|
||||
WHERE auteur='Asimov' AND ann_publi>1953
|
||||
```
|
||||
|
||||
Vérifiez que nous obtenons bien le livre écrit par Asimov publié après 1953.
|
||||
Vérifiez que vous obtenez bien les livres écrits par Asimov publiés après 1953.
|
||||
|
||||
8. Écrivez une requête permettant d'obtenir les titres des livres publiés après 1945 qui ont une note supérieure ou égale à 9.
|
||||
|
||||
@@ -253,7 +255,7 @@ VALUES
|
||||
14. À l'aide d'une requête SQL, ajoutez à la table LIVRES le livre suivant :
|
||||
- id : 17
|
||||
- titre : "2001 : L'Odyssée de l'espace"
|
||||
- auteur : "Clarcke"
|
||||
- auteur : "Clarke"
|
||||
- année de publication : 1968
|
||||
- note : 7
|
||||
|
||||
@@ -264,8 +266,15 @@ VALUES
|
||||
|
||||
--------
|
||||
|
||||
Source :
|
||||
Source :
|
||||
|
||||
- [Pixees, site de David Roche](https://informatique-lycee.forge.apps.education.fr/terminale_nsi/cours-terminale/c3a/)
|
||||
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
|
||||
|
||||
359
SQL/TP_Streaming_Musical.md
Normal file
359
SQL/TP_Streaming_Musical.md
Normal file
@@ -0,0 +1,359 @@
|
||||
# TP : Base de données d'un service de streaming musical
|
||||
|
||||
## Contexte
|
||||
|
||||
Vous êtes data analyst chez **Musicfy**, un service de streaming musical concurrent de Spotify et Deezer. Votre mission est d'analyser les données d'écoute pour comprendre les habitudes des utilisateurs et proposer des améliorations.
|
||||
|
||||
Vous disposez d'une base de données contenant les informations sur les artistes, albums, titres, utilisateurs et leurs écoutes.
|
||||
|
||||
---
|
||||
|
||||
## Objectifs
|
||||
|
||||
- Pratiquer les requêtes SQL sur une base de données réaliste
|
||||
- Maîtriser les jointures entre plusieurs tables
|
||||
- Utiliser les fonctions d'agrégation pour l'analyse de données
|
||||
- Comprendre l'organisation d'une base de données relationnelle
|
||||
|
||||
---
|
||||
|
||||
## Partie 1 : Découverte de la base de données
|
||||
|
||||
### 1.1. Création de la base
|
||||
|
||||
1. Ouvrez **DB Browser for SQLite** et créez une nouvelle base de données `musicfy.db`.
|
||||
|
||||
2. Exécutez les requêtes suivantes pour créer les tables :
|
||||
|
||||
```sql
|
||||
-- Table des artistes
|
||||
CREATE TABLE ARTISTES (
|
||||
id INTEGER PRIMARY KEY,
|
||||
nom TEXT NOT NULL,
|
||||
pays TEXT,
|
||||
genre_principal TEXT,
|
||||
ann_debut INTEGER
|
||||
);
|
||||
|
||||
-- Table des albums
|
||||
CREATE TABLE ALBUMS (
|
||||
id INTEGER PRIMARY KEY,
|
||||
titre TEXT NOT NULL,
|
||||
id_artiste INTEGER,
|
||||
ann_sortie INTEGER,
|
||||
nb_titres INTEGER,
|
||||
FOREIGN KEY (id_artiste) REFERENCES ARTISTES(id)
|
||||
);
|
||||
|
||||
-- Table des titres (chansons)
|
||||
CREATE TABLE TITRES (
|
||||
id INTEGER PRIMARY KEY,
|
||||
nom TEXT NOT NULL,
|
||||
id_album INTEGER,
|
||||
duree_sec INTEGER,
|
||||
explicite BOOLEAN DEFAULT FALSE,
|
||||
FOREIGN KEY (id_album) REFERENCES ALBUMS(id)
|
||||
);
|
||||
|
||||
-- Table des utilisateurs
|
||||
CREATE TABLE UTILISATEURS (
|
||||
id INTEGER PRIMARY KEY,
|
||||
pseudo TEXT NOT NULL,
|
||||
email TEXT UNIQUE,
|
||||
pays TEXT,
|
||||
type_abo TEXT DEFAULT 'gratuit',
|
||||
date_inscription DATE
|
||||
);
|
||||
|
||||
-- Table des écoutes
|
||||
CREATE TABLE ECOUTES (
|
||||
id INTEGER PRIMARY KEY,
|
||||
id_utilisateur INTEGER,
|
||||
id_titre INTEGER,
|
||||
date_ecoute DATE,
|
||||
duree_ecoute_sec INTEGER,
|
||||
FOREIGN KEY (id_utilisateur) REFERENCES UTILISATEURS(id),
|
||||
FOREIGN KEY (id_titre) REFERENCES TITRES(id)
|
||||
);
|
||||
```
|
||||
|
||||
### 1.2. Insertion des données
|
||||
|
||||
Exécutez les requêtes suivantes pour insérer les données :
|
||||
|
||||
```sql
|
||||
-- Artistes
|
||||
INSERT INTO ARTISTES (id, nom, pays, genre_principal, ann_debut) VALUES
|
||||
(1, 'Daft Punk', 'France', 'Electro', 1993),
|
||||
(2, 'Kendrick Lamar', 'USA', 'Hip-Hop', 2004),
|
||||
(3, 'Adele', 'Royaume-Uni', 'Pop', 2006),
|
||||
(4, 'BTS', 'Corée du Sud', 'K-Pop', 2013),
|
||||
(5, 'Stromae', 'Belgique', 'Electro', 2009),
|
||||
(6, 'Taylor Swift', 'USA', 'Pop', 2004),
|
||||
(7, 'PNL', 'France', 'Hip-Hop', 2014),
|
||||
(8, 'Beyoncé', 'USA', 'R&B', 1997),
|
||||
(9, 'Ed Sheeran', 'Royaume-Uni', 'Pop', 2004),
|
||||
(10, 'Aya Nakamura', 'France', 'Pop', 2014);
|
||||
|
||||
-- Albums
|
||||
INSERT INTO ALBUMS (id, titre, id_artiste, ann_sortie, nb_titres) VALUES
|
||||
(1, 'Random Access Memories', 1, 2013, 13),
|
||||
(2, 'Discovery', 1, 2001, 14),
|
||||
(3, 'DAMN.', 2, 2017, 14),
|
||||
(4, 'To Pimp a Butterfly', 2, 2015, 16),
|
||||
(5, '21', 3, 2011, 11),
|
||||
(6, '30', 3, 2021, 12),
|
||||
(7, 'Map of the Soul: 7', 4, 2020, 20),
|
||||
(8, 'Racine carrée', 5, 2013, 13),
|
||||
(9, 'Multitude', 5, 2022, 12),
|
||||
(10, '1989', 6, 2014, 13),
|
||||
(11, 'Midnights', 6, 2022, 13),
|
||||
(12, 'Dans la légende', 7, 2016, 17),
|
||||
(13, 'Deux frères', 7, 2019, 18),
|
||||
(14, 'Lemonade', 8, 2016, 12),
|
||||
(15, 'Renaissance', 8, 2022, 16),
|
||||
(16, 'Divide', 9, 2017, 16),
|
||||
(17, 'Nakamura', 10, 2018, 14),
|
||||
(18, 'DNK', 10, 2023, 15);
|
||||
|
||||
-- Titres (sélection)
|
||||
INSERT INTO TITRES (id, nom, id_album, duree_sec, explicite) VALUES
|
||||
(1, 'Get Lucky', 1, 369, FALSE),
|
||||
(2, 'Instant Crush', 1, 337, FALSE),
|
||||
(3, 'Lose Yourself to Dance', 1, 353, FALSE),
|
||||
(4, 'One More Time', 2, 320, FALSE),
|
||||
(5, 'Digital Love', 2, 301, FALSE),
|
||||
(6, 'Harder Better Faster Stronger', 2, 224, FALSE),
|
||||
(7, 'HUMBLE.', 3, 177, TRUE),
|
||||
(8, 'DNA.', 3, 185, TRUE),
|
||||
(9, 'LOYALTY.', 3, 227, TRUE),
|
||||
(10, 'Alright', 4, 219, TRUE),
|
||||
(11, 'King Kunta', 4, 234, TRUE),
|
||||
(12, 'Rolling in the Deep', 5, 228, FALSE),
|
||||
(13, 'Someone Like You', 5, 285, FALSE),
|
||||
(14, 'Set Fire to the Rain', 5, 241, FALSE),
|
||||
(15, 'Easy On Me', 6, 224, FALSE),
|
||||
(16, 'Oh My My', 6, 218, FALSE),
|
||||
(17, 'Dynamite', 7, 199, FALSE),
|
||||
(18, 'ON', 7, 242, FALSE),
|
||||
(19, 'Papaoutai', 8, 234, FALSE),
|
||||
(20, 'Formidable', 8, 192, FALSE),
|
||||
(21, 'Alors on danse', 8, 205, FALSE),
|
||||
(22, 'Santé', 9, 188, FALSE),
|
||||
(23, 'L''enfer', 9, 224, FALSE),
|
||||
(24, 'Shake It Off', 10, 219, FALSE),
|
||||
(25, 'Blank Space', 10, 231, FALSE),
|
||||
(26, 'Style', 10, 231, FALSE),
|
||||
(27, 'Anti-Hero', 11, 201, FALSE),
|
||||
(28, 'Lavender Haze', 11, 202, FALSE),
|
||||
(29, 'Le monde ou rien', 12, 228, TRUE),
|
||||
(30, 'DA', 12, 195, TRUE),
|
||||
(31, 'Au DD', 13, 199, TRUE),
|
||||
(32, 'A l''ammoniaque', 13, 234, TRUE),
|
||||
(33, 'Formation', 14, 226, TRUE),
|
||||
(34, 'Sorry', 14, 232, FALSE),
|
||||
(35, 'BREAK MY SOUL', 15, 279, FALSE),
|
||||
(36, 'CUFF IT', 15, 225, FALSE),
|
||||
(37, 'Shape of You', 16, 233, FALSE),
|
||||
(38, 'Castle on the Hill', 16, 261, FALSE),
|
||||
(39, 'Perfect', 16, 263, FALSE),
|
||||
(40, 'Djadja', 17, 176, FALSE),
|
||||
(41, 'Pookie', 17, 185, TRUE),
|
||||
(42, 'Copines', 18, 179, FALSE),
|
||||
(43, 'SMS', 18, 164, FALSE);
|
||||
|
||||
-- Utilisateurs
|
||||
INSERT INTO UTILISATEURS (id, pseudo, email, pays, type_abo, date_inscription) VALUES
|
||||
(1, 'music_lover_33', 'music33@email.com', 'France', 'premium', '2020-03-15'),
|
||||
(2, 'alex_beats', 'alex.b@email.com', 'France', 'gratuit', '2021-06-22'),
|
||||
(3, 'sophie_melody', 'sophie.m@email.com', 'Belgique', 'premium', '2019-11-08'),
|
||||
(4, 'dj_max', 'maxime.dj@email.com', 'France', 'famille', '2022-01-10'),
|
||||
(5, 'luna_music', 'luna.music@email.com', 'Canada', 'etudiant', '2021-09-01'),
|
||||
(6, 'kevin_hiphop', 'kevin.hh@email.com', 'USA', 'premium', '2020-07-19'),
|
||||
(7, 'emma_pop', 'emma.pop@email.com', 'Royaume-Uni', 'gratuit', '2023-02-28'),
|
||||
(8, 'thomas_electro', 'thomas.e@email.com', 'France', 'premium', '2018-05-12'),
|
||||
(9, 'clara_world', 'clara.w@email.com', 'Espagne', 'etudiant', '2022-10-05'),
|
||||
(10, 'jp_kpop', 'jp.kpop@email.com', 'Japon', 'premium', '2021-03-20');
|
||||
|
||||
-- Écoutes (échantillon)
|
||||
INSERT INTO ECOUTES (id, id_utilisateur, id_titre, date_ecoute, duree_ecoute_sec) VALUES
|
||||
(1, 1, 1, '2024-01-15', 369),
|
||||
(2, 1, 4, '2024-01-15', 320),
|
||||
(3, 1, 19, '2024-01-15', 234),
|
||||
(4, 2, 7, '2024-01-15', 177),
|
||||
(5, 2, 8, '2024-01-15', 150),
|
||||
(6, 2, 29, '2024-01-15', 228),
|
||||
(7, 3, 19, '2024-01-16', 234),
|
||||
(8, 3, 20, '2024-01-16', 192),
|
||||
(9, 3, 22, '2024-01-16', 188),
|
||||
(10, 4, 1, '2024-01-16', 369),
|
||||
(11, 4, 6, '2024-01-16', 224),
|
||||
(12, 5, 17, '2024-01-16', 199),
|
||||
(13, 5, 18, '2024-01-16', 242),
|
||||
(14, 6, 7, '2024-01-17', 177),
|
||||
(15, 6, 10, '2024-01-17', 219),
|
||||
(16, 6, 11, '2024-01-17', 234),
|
||||
(17, 7, 12, '2024-01-17', 228),
|
||||
(18, 7, 24, '2024-01-17', 219),
|
||||
(19, 7, 37, '2024-01-17', 233),
|
||||
(20, 8, 1, '2024-01-17', 369),
|
||||
(21, 8, 4, '2024-01-17', 320),
|
||||
(22, 8, 5, '2024-01-17', 301),
|
||||
(23, 8, 6, '2024-01-17', 224),
|
||||
(24, 9, 40, '2024-01-18', 176),
|
||||
(25, 9, 42, '2024-01-18', 179),
|
||||
(26, 10, 17, '2024-01-18', 199),
|
||||
(27, 10, 18, '2024-01-18', 242),
|
||||
(28, 1, 19, '2024-01-18', 234),
|
||||
(29, 1, 21, '2024-01-18', 205),
|
||||
(30, 2, 31, '2024-01-18', 199),
|
||||
(31, 3, 23, '2024-01-19', 224),
|
||||
(32, 4, 35, '2024-01-19', 279),
|
||||
(33, 5, 27, '2024-01-19', 201),
|
||||
(34, 6, 8, '2024-01-19', 185),
|
||||
(35, 7, 39, '2024-01-19', 263),
|
||||
(36, 8, 2, '2024-01-19', 337),
|
||||
(37, 9, 41, '2024-01-20', 185),
|
||||
(38, 10, 17, '2024-01-20', 199),
|
||||
(39, 1, 1, '2024-01-20', 369),
|
||||
(40, 2, 7, '2024-01-20', 177);
|
||||
```
|
||||
|
||||
### 1.3. Schéma de la base
|
||||
|
||||
Dessinez le schéma relationnel de la base de données en identifiant :
|
||||
- Les clés primaires (PK)
|
||||
- Les clés étrangères (FK)
|
||||
- Les relations entre les tables
|
||||
|
||||
---
|
||||
|
||||
## Partie 2 : Requêtes de base
|
||||
|
||||
**Pour chaque question, écrivez la requête SQL et notez le résultat.**
|
||||
|
||||
1. Affichez tous les artistes de la base de données.
|
||||
|
||||
2. Affichez le nom et le pays des artistes français.
|
||||
|
||||
3. Affichez les titres de tous les albums sortis après 2015.
|
||||
|
||||
4. Affichez les pseudos des utilisateurs ayant un abonnement premium.
|
||||
|
||||
5. Affichez les titres (chansons) qui durent plus de 4 minutes (240 secondes).
|
||||
|
||||
6. Affichez les artistes dont le genre principal est "Hip-Hop" ou "Pop".
|
||||
|
||||
---
|
||||
|
||||
## Partie 3 : Requêtes avec jointures
|
||||
|
||||
7. Affichez le nom des titres avec le nom de leur album.
|
||||
|
||||
8. Affichez le nom des titres avec le nom de l'artiste qui les a créés.
|
||||
*(Indice : vous devez passer par la table ALBUMS)*
|
||||
|
||||
9. Affichez les albums de Daft Punk avec leur année de sortie.
|
||||
|
||||
10. Affichez la liste des écoutes avec le pseudo de l'utilisateur et le nom du titre écouté.
|
||||
|
||||
11. Affichez tous les titres des artistes français.
|
||||
|
||||
12. Pour chaque écoute, affichez le pseudo de l'utilisateur, le nom du titre, le nom de l'album et le nom de l'artiste.
|
||||
|
||||
---
|
||||
|
||||
## Partie 4 : Agrégations
|
||||
|
||||
13. Combien y a-t-il de titres dans la base de données ?
|
||||
|
||||
14. Quelle est la durée moyenne des titres (en secondes) ?
|
||||
|
||||
15. Quel est le titre le plus long ? Le plus court ?
|
||||
|
||||
16. Combien d'albums a sorti chaque artiste ? Affichez le nom de l'artiste et le nombre d'albums.
|
||||
|
||||
17. Combien d'écoutes ont été effectuées par chaque utilisateur ? Affichez le pseudo et le nombre d'écoutes.
|
||||
|
||||
18. Quel est le nombre total de titres par genre musical ?
|
||||
*(Indice : il faut passer par ARTISTES et ALBUMS)*
|
||||
|
||||
---
|
||||
|
||||
## Partie 5 : Requêtes avancées
|
||||
|
||||
19. Quels sont les artistes ayant sorti plus d'un album ?
|
||||
|
||||
20. Quels sont les 5 titres les plus écoutés ? Affichez le nom du titre et le nombre d'écoutes.
|
||||
|
||||
21. Quels utilisateurs ont écouté des titres de Stromae ?
|
||||
|
||||
22. Quelle est la durée totale d'écoute (en minutes) par utilisateur ?
|
||||
|
||||
23. Quels artistes n'ont aucun titre explicite dans leurs chansons ?
|
||||
|
||||
24. Pour chaque pays d'utilisateur, calculez le nombre d'écoutes et la durée totale d'écoute.
|
||||
|
||||
---
|
||||
|
||||
## Partie 6 : Analyse business
|
||||
|
||||
Le département marketing vous demande des analyses pour améliorer le service.
|
||||
|
||||
25. **Taux de conversion** : Combien d'utilisateurs ont un abonnement payant (premium, famille ou étudiant) vs gratuit ?
|
||||
|
||||
26. **Artistes populaires en France** : Quels artistes sont les plus écoutés par les utilisateurs français ?
|
||||
|
||||
27. **Recommandations** : Trouvez les utilisateurs qui ont écouté Daft Punk mais pas Stromae (ces utilisateurs pourraient aimer Stromae).
|
||||
|
||||
28. **Contenu explicite** : Quel pourcentage des titres est marqué comme explicite ?
|
||||
|
||||
29. **Rétention** : Quels utilisateurs inscrits avant 2021 ont écouté de la musique en janvier 2024 ?
|
||||
|
||||
30. **Rapport final** : Créez une vue synthétique montrant pour chaque artiste : son nom, son pays, son genre, le nombre d'albums, le nombre de titres et le nombre total d'écoutes.
|
||||
|
||||
---
|
||||
|
||||
## Partie 7 : Modifications de données (Bonus)
|
||||
|
||||
31. Ajoutez l'artiste "Angèle" (Belgique, Pop, 2014).
|
||||
|
||||
32. Ajoutez son album "Brol" sorti en 2018 avec 15 titres.
|
||||
|
||||
33. Un utilisateur change d'abonnement : mettez à jour `alex_beats` vers l'abonnement "etudiant".
|
||||
|
||||
34. Supprimez toutes les écoutes de l'utilisateur `jp_kpop`.
|
||||
|
||||
---
|
||||
|
||||
## Questions de réflexion
|
||||
|
||||
1. Pourquoi a-t-on séparé les artistes et les albums dans des tables différentes au lieu de tout mettre dans une seule table ?
|
||||
|
||||
2. Quel problème pourrait survenir si on supprimait un artiste qui a des albums dans la base ?
|
||||
|
||||
3. Comment pourrait-on améliorer la base pour gérer les collaborations entre artistes sur un même titre ?
|
||||
|
||||
4. Quelles informations supplémentaires pourrait-on ajouter pour un vrai service de streaming ?
|
||||
|
||||
---
|
||||
|
||||
## Barème indicatif
|
||||
|
||||
| Partie | Points |
|
||||
|--------|--------|
|
||||
| Partie 1 : Création et schéma | 2 |
|
||||
| Partie 2 : Requêtes de base | 3 |
|
||||
| Partie 3 : Jointures | 4 |
|
||||
| Partie 4 : Agrégations | 4 |
|
||||
| Partie 5 : Requêtes avancées | 4 |
|
||||
| Partie 6 : Analyse business | 3 |
|
||||
| **Total** | **20** |
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
BIN
SQL/assets/sql_join.JPG
Normal file
BIN
SQL/assets/sql_join.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 91 KiB |
Reference in New Issue
Block a user