C'est une très bonne question, j'ai donc décidé d'écrire un article très détaillé sur ce sujet sur mon blog.
Modèle de table de base de données
Supposons que nous avons les deux tables suivantes dans notre base de données, qui forment une relation de table un-à-plusieurs.
La student
table est le parent et la student_grade
table enfant car elle possède une colonne Student_id Foreign Key faisant référence à la colonne id Primary Key dans la table student.
Le student table
contient les deux enregistrements suivants:
| id | first_name | last_name | admission_score |
|----|------------|-----------|-----------------|
| 1 | Alice | Smith | 8.95 |
| 2 | Bob | Johnson | 8.75 |
Et, la student_grade
table stocke les notes que les étudiants ont reçues:
| id | class_name | grade | student_id |
|----|------------|-------|------------|
| 1 | Math | 10 | 1 |
| 2 | Math | 9.5 | 1 |
| 3 | Math | 9.75 | 1 |
| 4 | Science | 9.5 | 1 |
| 5 | Science | 9 | 1 |
| 6 | Science | 9.25 | 1 |
| 7 | Math | 8.5 | 2 |
| 8 | Math | 9.5 | 2 |
| 9 | Math | 9 | 2 |
| 10 | Science | 10 | 2 |
| 11 | Science | 9.4 | 2 |
SQL EXISTS
Disons que nous voulons obtenir tous les élèves qui ont reçu une note de 10 en classe de mathématiques.
Si nous ne sommes intéressés que par l'identifiant de l'élève, nous pouvons exécuter une requête comme celle-ci:
SELECT
student_grade.student_id
FROM
student_grade
WHERE
student_grade.grade = 10 AND
student_grade.class_name = 'Math'
ORDER BY
student_grade.student_id
Mais, l'application est intéressée à afficher le nom complet d'un student
, pas seulement l'identifiant, nous avons donc également besoin des informations de la student
table.
Afin de filtrer les student
enregistrements qui ont une note de 10 en mathématiques, nous pouvons utiliser l'opérateur SQL EXISTS, comme ceci:
SELECT
id, first_name, last_name
FROM
student
WHERE EXISTS (
SELECT 1
FROM
student_grade
WHERE
student_grade.student_id = student.id AND
student_grade.grade = 10 AND
student_grade.class_name = 'Math'
)
ORDER BY id
Lors de l'exécution de la requête ci-dessus, nous pouvons voir que seule la ligne Alice est sélectionnée:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
La requête externe sélectionne les student
colonnes de lignes que nous souhaitons renvoyer au client. Cependant, la clause WHERE utilise l'opérateur EXISTS avec une sous-requête interne associée.
L'opérateur EXISTS renvoie true si la sous-requête renvoie au moins un enregistrement et false si aucune ligne n'est sélectionnée. Le moteur de base de données n'a pas à exécuter entièrement la sous-requête. Si un seul enregistrement correspond, l'opérateur EXISTS renvoie true et l'autre ligne de requête associée est sélectionnée.
La sous-requête interne est corrélée car la colonne student_id de la student_grade
table est comparée à la colonne id de la table student externe.
SQL N'EXISTE PAS
Considérons que nous voulons sélectionner tous les élèves qui n'ont pas de note inférieure à 9. Pour cela, nous pouvons utiliser NOT EXISTS, ce qui annule la logique de l'opérateur EXISTS.
Par conséquent, l'opérateur NOT EXISTS renvoie true si la sous-requête sous-jacente ne renvoie aucun enregistrement. Cependant, si un seul enregistrement correspond à la sous-requête interne, l'opérateur NOT EXISTS renvoie false et l'exécution de la sous-requête peut être arrêtée.
Pour faire correspondre tous les enregistrements d'étudiant qui n'ont pas de student_grade associé avec une valeur inférieure à 9, nous pouvons exécuter la requête SQL suivante:
SELECT
id, first_name, last_name
FROM
student
WHERE NOT EXISTS (
SELECT 1
FROM
student_grade
WHERE
student_grade.student_id = student.id AND
student_grade.grade < 9
)
ORDER BY id
Lors de l'exécution de la requête ci-dessus, nous pouvons voir que seul l'enregistrement Alice est mis en correspondance:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
Ainsi, l'avantage d'utiliser les opérateurs SQL EXISTS et NOT EXISTS est que l'exécution de la sous-requête interne peut être arrêtée tant qu'un enregistrement correspondant est trouvé.