Это очень хороший вопрос, поэтому я решил написать очень подробную статью на эту тему в своем блоге.
Модель таблицы базы данных
Предположим, у нас есть две таблицы в нашей базе данных, которые образуют отношение таблицы «один ко многим».
student
Таблица является родителем, и student_grade
является дочерней таблицей , так как он имеет student_id столбец внешнего ключа , ссылающийся Ид столбец первичного ключа в таблице студента.
student table
Содержит следующие две записи:
| id | first_name | last_name | admission_score |
|----|------------|-----------|-----------------|
| 1 | Alice | Smith | 8.95 |
| 2 | Bob | Johnson | 8.75 |
И в student_grade
таблице хранятся оценки, полученные студентами:
| 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 СУЩЕСТВУЕТ
Допустим, мы хотим, чтобы все ученики получили 10 баллов по математике.
Если нас интересует только идентификатор студента, мы можем выполнить запрос, подобный следующему:
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
Но приложение заинтересовано в отображении полного имени, а student
не только идентификатора, поэтому нам также нужна информация из student
таблицы.
Чтобы отфильтровать student
записи, которые имеют 10 баллов по математике, мы можем использовать оператор EXISTS SQL, например:
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
При выполнении запроса выше, мы видим, что выбрана только строка Алиса:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
Внешний запрос выбирает student
столбцы строк, которые мы хотим вернуть клиенту. Однако в предложении WHERE используется оператор EXISTS со связанным внутренним подзапросом.
Оператор EXISTS возвращает true, если подзапрос возвращает хотя бы одну запись, и false, если строка не выбрана. Механизм базы данных не должен полностью выполнять подзапрос. Если сопоставляется одна запись, оператор EXISTS возвращает true и выбирается связанная строка запроса.
Внутренний подзапрос коррелируется, потому что столбец student_id student_grade
таблицы сопоставляется со столбцом id внешней таблицы студентов.
SQL НЕ СУЩЕСТВУЕТ
Давайте рассмотрим, что мы хотим выбрать всех учеников, у которых оценка не ниже 9. Для этого мы можем использовать NOT EXISTS, что сводит на нет логику оператора EXISTS.
Следовательно, оператор NOT EXISTS возвращает true, если базовый подзапрос не возвращает запись. Однако, если внутреннему подзапросу соответствует одна запись, оператор NOT EXISTS вернет false, и выполнение подзапроса может быть остановлено.
Чтобы сопоставить все записи учеников, у которых нет связанных student_grade со значением ниже 9, мы можем выполнить следующий запрос SQL:
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
При выполнении запроса выше мы видим, что сопоставляется только запись Алисы:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
Таким образом, преимущество использования операторов SQL EXISTS и NOT EXISTS состоит в том, что выполнение внутреннего подзапроса может быть остановлено, если найдена соответствующая запись.