EXISTS i NOT EXISTS
Wydajnie sprawdzaj istnienie powiązanych wierszy
EXISTS i NOT EXISTS to bezpłatna lekcja SQL Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej SQL Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs SQL Academy zawiera 4 lekcji w sumie.
Czym jest EXISTS?
Operator EXISTS sprawdza, czy podzapytanie zwraca co najmniej jeden wiersz. Jego wynikiem jest TRUE, jeśli podzapytanie zwróci dowolny wynik, oraz FALSE, jeśli jest puste.
W przeciwieństwie do innych operatorów podzapytań, które porównują wartości, EXISTS interesuje się wyłącznie obecnością — nie analizuje faktycznych danych zwróconych przez podzapytanie.
Przygotowanie przykładowych tabel
Przed napisaniem zapytań z EXISTS należy utworzyć dwie tabele: customers i orders. Będziemy ich używać w całej lekcji, aby poznać praktyczne działanie EXISTS i NOT EXISTS.
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
name VARCHAR(100),
country VARCHAR(50)
);
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
amount DECIMAL(10,2),
order_date DATE
);
INSERT INTO customers VALUES
(1, 'Alice', 'US'),
(2, 'Bob', 'UK'),
(3, 'Charlie', 'US'),
(4, 'Diana', 'DE');
INSERT INTO orders VALUES
(101, 1, 250.00, '2024-01-10'),
(102, 1, 180.00, '2024-02-15'),
(103, 2, 95.00, '2024-03-01'),
(104, 3, 430.00, '2024-03-22');Podstawowa składnia EXISTS
Podstawowa składnia EXISTS umieszcza go w klauzuli WHERE. Podzapytanie znajdujące się wewnątrz EXISTS zwykle odwołuje się do kolumny z zapytania zewnętrznego — nazywa się je wtedy skorelowanym podzapytaniem.
Poniższe zapytanie znajduje każdego klienta, który złożył co najmniej jedno zamówienie.
SELECT customer_id, name
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
);SELECT 1 w EXISTS
Być może zauważyli Państwo, że zapytanie podrzędne używa SELECT 1, zamiast wybierać rzeczywistą kolumnę. Jest to zamierzone — EXISTS sprawdza tylko, czy wiersze istnieją, a nie co zawierają.
Użycie SELECT 1 (lub nawet SELECT *) nie wpływa na wynik, ale SELECT 1 jasno sygnalizuje zarówno silnikowi bazy danych, jak i osobie czytającej zapytanie, że rzeczywiste wartości nie mają znaczenia.
-- Both of these return the same result
SELECT name FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id);
SELECT name FROM customers c
WHERE EXISTS (SELECT o.* FROM orders o WHERE o.customer_id = c.customer_id);Jak baza danych ocenia EXISTS
Dla każdego wiersza zapytania zewnętrznego baza danych wykonuje skorelowane zapytanie podrzędne. Gdy tylko zostanie znaleziony jeden pasujący wiersz, silnik przerywa skanowanie i oznacza EXISTS jako TRUE — ta ewaluacja z krótkim spięciem sprawia, że EXISTS jest bardzo wydajne nawet w przypadku dużych tabel.
Natomiast JOIN utworzyłby pełny zbiór pasujących wierszy przed filtrowaniem, co może być wolniejsze, gdy trzeba tylko sprawdzić, czy istnieje dopasowanie.
-- EXISTS short-circuits after first match
-- Efficient even when orders table has millions of rows
SELECT name, country
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
AND o.amount > 200
);NOT EXISTS: znajdowanie brakujących wierszy
NOT EXISTS działa odwrotnie: zwraca TRUE, gdy zapytanie podrzędne nie znajdzie żadnego pasującego wiersza. Jest to standardowy sposób SQL na uzyskanie odpowiedzi na pytania takie jak "którzy klienci nigdy nie złożyli zamówienia?"
Próba rozwiązania tego za pomocą zwykłego JOIN lub NOT IN może prowadzić do nieprawidłowych wyników, gdy występują wartości NULL — NOT EXISTS całkowicie unika tego problemu.
-- Customers who have NOT placed any order
SELECT customer_id, name
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
);NOT EXISTS a NOT IN z wartościami NULL
Jedną z kluczowych zalet NOT EXISTS w porównaniu z NOT IN jest bezpieczeństwo w przypadku wartości NULL. Jeśli zapytanie podrzędne używane przez NOT IN zwróci choć jedną wartość NULL, całe wyrażenie NOT IN stanie się NULL — co oznacza, że zapytanie zewnętrzne nie zwróci żadnych wierszy.
NOT EXISTS nie ma tego problemu, ponieważ sprawdza istnienie wiersza, a nie równość wartości.
-- Dangerous: if any customer_id in orders is NULL,
-- NOT IN returns zero rows!
SELECT name FROM customers
WHERE customer_id NOT IN (SELECT customer_id FROM orders);
-- Safe: NOT EXISTS handles NULLs correctly
SELECT name FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM orders o
WHERE o.customer_id = c.customer_id
);EXISTS z wieloma warunkami
Zapytanie podrzędne wewnątrz EXISTS może zawierać dowolny prawidłowy kod SQL, w tym wiele warunków WHERE. Dzięki temu można sprawdzać bardzo konkretne powiązane wiersze — na przykład klientów, którzy złożyli zamówienie o wartości przekraczającej określony próg w konkretnym miesiącu.
-- Customers who placed an order over 200 in March 2024
SELECT c.name, c.country
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customer_id
AND o.amount > 200
AND o.order_date >= '2024-03-01'
AND o.order_date < '2024-04-01'
);EXISTS w DELETE i UPDATE
EXISTS nie jest ograniczone do instrukcji SELECT. Można używać go w UPDATE i DELETE, aby modyfikować lub usuwać wiersze na podstawie istnienia powiązanych danych w innej tabeli.
Poniższy przykład usuwa zamówienia należące do klientów z określonego kraju.
-- Delete orders placed by US customers
DELETE FROM orders o
WHERE EXISTS (
SELECT 1
FROM customers c
WHERE c.customer_id = o.customer_id
AND c.country = 'US'
);Porównanie EXISTS z JOIN
EXISTS i JOIN często pozwalają wyrazić to samo pytanie, ale działają inaczej. JOIN zwielokrotnia wiersze, gdy istnieje wiele dopasowań, natomiast EXISTS zawsze zwraca każdy wiersz zewnętrzny najwyżej raz.
Jeśli trzeba tylko sprawdzić, czy istnieje relacja, a nie pobrać dane z powiązanej tabeli, EXISTS jest czytelniejsze i zazwyczaj szybsze.
-- JOIN may return duplicate customer rows if a customer has multiple orders
SELECT DISTINCT c.name
FROM customers c
JOIN orders o ON o.customer_id = c.customer_id;
-- EXISTS always returns each customer once
SELECT c.name
FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.customer_id = c.customer_id
);NOT EXISTS do kontroli jakości danych
NOT EXISTS jest potężnym narzędziem do audytów jakości danych. Można używać go do znajdowania osieroconych rekordów, brakujących odwołań lub wierszy, które powinny mieć powiązane dane, ale ich nie mają.
Poniższe zapytanie wykrywa wiersze zamówień, których customer_id nie odpowiada żadnemu wierszowi w tabeli customers — jest to oznaka naruszenia integralności referencyjnej.
-- Find orders with no matching customer (orphaned records)
SELECT o.order_id, o.customer_id, o.amount
FROM orders o
WHERE NOT EXISTS (
SELECT 1
FROM customers c
WHERE c.customer_id = o.customer_id
);Szybkie sprawdzenie
Sprawdź, czy rozumieją Państwo działanie EXISTS i NOT EXISTS.
Podsumowanie lekcji
W tej lekcji dowiedzieli się Państwo, jak EXISTS i NOT EXISTS pozwalają sprawdzać obecność lub brak powiązanych wierszy bez bezpośredniego porównywania wartości.
Najważniejsze wnioski:
- EXISTS zwraca TRUE, gdy tylko zapytanie podrzędne znajdzie jeden pasujący wiersz (ewaluacja z krótkim spięciem).
- NOT EXISTS zwraca TRUE, gdy zapytanie podrzędne nie znajdzie żadnych pasujących wierszy.
- W EXISTS należy używać
SELECT 1— zwracane wartości nie mają znaczenia. - NOT EXISTS bezpiecznie obsługuje wartości NULL, a NOT IN nie — gdy mogą wystąpić wartości NULL, należy preferować NOT EXISTS.
- EXISTS działa w instrukcjach SELECT, UPDATE i DELETE.
- Gdy potrzebne jest tylko sprawdzenie istnienia, EXISTS jest często czytelniejsze i szybsze niż JOIN.
Ucz się SQL dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 46
- Lekcje
- 183
Często zadawane pytania
Czy lekcja „EXISTS i NOT EXISTS” jest bezpłatna?
Tak — pełny tekst „EXISTS i NOT EXISTS” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu SQL Academy, przejdź na CoddyKit PRO. Kurs SQL Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „EXISTS i NOT EXISTS”?
Wydajnie sprawdzaj istnienie powiązanych wierszy Ćwiczysz SQL Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć SQL Academy?
Nie wymagamy żadnego doświadczenia. SQL Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „EXISTS i NOT EXISTS”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji SQL Academy?
Tak. Każda lekcja SQL Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Podzapytania skorelowane
- EXISTS i NOT EXISTS
- IN a ANY i ALL
- Wydajność EXISTS a JOIN