To bardzo dobre pytanie, dlatego postanowiłem napisać bardzo szczegółowy artykuł na ten temat na moim blogu.
Model tabeli bazy danych
Załóżmy, że mamy w naszej bazie danych następujące dwie tabele, które tworzą relację jeden do wielu.
student
Stół jest rodzicem, astudent_grade
to tabela dziecko, ponieważ ma to student_id kolumny klucz obcy odniesienia do identyfikatora kolumny klucza podstawowego w tabeli studentów.
student table
Zawiera następujące dwa rekordy:
| id | first_name | last_name | admission_score |
|----|------------|-----------|-----------------|
| 1 | Alice | Smith | 8.95 |
| 2 | Bob | Johnson | 8.75 |
, A student_grade
tabela przechowuje klas otrzymali uczniowie:
| 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 |
ISTNIEJE SQL
Powiedzmy, że chcemy, aby wszyscy uczniowie, którzy otrzymali 10 klas z matematyki.
Jeśli interesuje nas tylko identyfikator studenta, możemy uruchomić zapytanie takie jak to:
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
Ale aplikacja jest zainteresowana wyświetlaniem pełnej nazwy, a student
nie tylko identyfikatora, dlatego potrzebujemy informacji zstudent
tabeli.
Aby filtrować student
rekordy, które mają 10 stopni z matematyki, możemy użyć operatora EXISTS SQL, takiego jak to:
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
Po uruchomieniu powyższego zapytania widzimy, że wybrany jest tylko wiersz Alice:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
Zewnętrzne zapytanie wybiera student
kolumny wierszy, które chcemy powrócić do klienta. Jednak klauzula WHERE korzysta z operatora EXISTS z powiązanym wewnętrznym podzapytaniem.
Operator EXISTS zwraca wartość true, jeśli podzapytanie zwraca co najmniej jeden rekord, a wartość false, jeśli nie wybrano żadnego wiersza. Aparat bazy danych nie musi całkowicie uruchamiać podkwerendy. Jeśli zostanie dopasowany pojedynczy rekord, operator EXISTS zwróci wartość true i wybrany zostanie powiązany inny wiersz zapytania.
Wewnętrzne podzapytanie jest skorelowane, ponieważ kolumna student_id w student_grade
tabeli jest dopasowana do kolumny id zewnętrznej tabeli studenta.
SQL NIE ISTNIEJE
Rozważmy, że chcemy wybrać wszystkich uczniów, którzy nie mają ocen niższych niż 9. W tym celu możemy użyć NOT EXISTS, co neguje logikę operatora EXISTS.
Dlatego operator NOT EXISTS zwraca true, jeśli bazowe podzapytanie nie zwraca rekordu. Jeśli jednak pojedynczy rekord zostanie dopasowany do wewnętrznego podzapytania, operator NOT EXISTS zwróci false, a wykonanie podzapytania można zatrzymać.
Aby dopasować wszystkie rekordy studentów, które nie mają skojarzonego student_grade z wartością mniejszą niż 9, możemy uruchomić następujące zapytanie 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
Po uruchomieniu powyższego zapytania widzimy, że dopasowany jest tylko rekord Alice:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
Zaletą korzystania z operatorów SQL EXISTS i NOT EXISTS jest to, że wykonywanie wewnętrznego podzapytania można zatrzymać, dopóki znaleziony zostanie pasujący rekord.