0Pricing
SQL Academy · 강의

EXISTS와 NOT EXISTS

관련 행이 있는지 효율적으로 확인합니다.

EXISTS와 NOT EXISTS은(는) CoddyKit의 무료 SQL Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 SQL Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. SQL Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

EXISTS란 무엇입니까?

EXISTS 연산자는 하위 질의가 하나 이상의 행을 반환하는지 확인합니다. 하위 질의가 어떤 결과라도 생성하면 TRUE로 평가되고, 하위 질의가 비어 있으면 FALSE로 평가됩니다.

값을 비교하는 다른 하위 질의 연산자와 달리 EXISTS는 존재 여부만 확인하며 하위 질의가 반환한 실제 데이터는 살펴보지 않습니다.

샘플 테이블 설정

EXISTS 질의를 작성하기 전에 두 테이블인 customers와 orders를 생성해 보겠습니다. 이 단원 전체에서 이 테이블을 사용하여 EXISTS와 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');

EXISTS 기본 구문

EXISTS의 기본 구문은 WHERE 절 안에 배치하는 것입니다. EXISTS 안의 하위 질의는 일반적으로 바깥 질의의 열을 참조하며, 이를 상관 하위 질의라고 합니다.

아래 질의는 주문을 하나 이상 등록한 모든 고객을 찾습니다.

SELECT customer_id, name
FROM customers c
WHERE EXISTS (
  SELECT 1
  FROM orders o
  WHERE o.customer_id = c.customer_id
);

EXISTS 내부의 SELECT 1

서브쿼리에서 실제 열을 선택하는 대신 SELECT 1을 사용하는 것을 눈치채셨을 수 있습니다. 이는 의도된 것입니다. EXISTS는 행이 무엇을 포함하는지가 아니라 행이 존재하는지만 확인합니다.

SELECT 1을 사용해도(또는 SELECT *를 사용해도) 결과에는 차이가 없지만, SELECT 1은 실제 값이 중요하지 않다는 점을 데이터베이스 엔진과 독자 모두에게 분명히 알려 줍니다.

-- 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);

데이터베이스가 EXISTS를 평가하는 방식

외부 쿼리의 각 행에 대해 데이터베이스는 상관 서브쿼리를 실행합니다. 일치하는 행을 하나라도 찾으면 엔진은 즉시 스캔을 중단하고 EXISTS를 TRUE로 표시합니다. 이 단락 평가 덕분에 EXISTS는 대규모 테이블에서도 매우 효율적입니다.

반면 JOIN은 필터링하기 전에 일치하는 행의 전체 집합을 구성하므로, 일치하는 항목이 존재하는지만 확인하면 될 때는 더 느릴 수 있습니다.

-- 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: 없는 행 찾기

NOT EXISTS는 그 반대입니다. 서브쿼리에서 일치하는 행을 하나도 찾지 못하면 TRUE를 반환합니다. 이는 "어떤 고객이 한 번도 주문하지 않았는가?"와 같은 질문에 답하는 표준 SQL 방식입니다.

일반 JOIN이나 NOT IN으로 이 문제를 해결하려고 하면 NULL이 관련된 경우 잘못된 결과가 나올 수 있지만, NOT EXISTS는 이러한 문제를 완전히 피합니다.

-- 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
);

NULL이 있을 때 NOT EXISTS와 NOT IN 비교

NOT IN보다 NOT EXISTS가 갖는 중요한 장점 중 하나는 NULL을 안전하게 처리한다는 점입니다. NOT IN에서 사용하는 서브쿼리가 NULL을 하나라도 반환하면 전체 NOT IN 표현식이 NULL이 됩니다. 그러면 외부 쿼리에서는 어떤 행도 반환되지 않습니다.

NOT EXISTS는 값의 동일성이 아니라 행의 존재 여부를 평가하므로 이 문제의 영향을 받지 않습니다.

-- 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

EXISTS 내부의 서브쿼리에는 여러 WHERE 조건을 비롯해 유효한 SQL을 무엇이든 포함할 수 있습니다. 이를 통해 매우 구체적인 관련 행이 있는지 확인할 수 있습니다. 예를 들어 특정 달에 임계값보다 큰 주문을 한 고객을 찾을 수 있습니다.

-- 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'
);

DELETE와 UPDATE에서 사용하는 EXISTS

EXISTS는 SELECT 문에만 사용할 수 있는 것이 아닙니다. UPDATE와 DELETE에서도 사용하여 다른 테이블의 관련 데이터가 존재하는지에 따라 행을 수정하거나 삭제할 수 있습니다.

아래 예시는 특정 국가의 고객에게 속한 주문을 삭제합니다.

-- 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'
);

EXISTS와 JOIN 비교

EXISTS와 JOIN은 같은 질문을 표현할 수 있지만 동작 방식이 다릅니다. JOIN은 일치하는 행이 여러 개면 행을 증식시키지만, EXISTS는 외부 행을 최대 한 번만 반환합니다.

관계가 존재하는지만 알고 관련 테이블의 데이터를 가져올 필요가 없다면 EXISTS가 더 간결하고 일반적으로 더 빠릅니다.

-- 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

NOT EXISTS는 데이터 품질을 감사할 때 유용한 강력한 도구입니다. 이를 사용하여 고아 레코드, 누락된 참조 또는 관련 데이터가 있어야 하지만 존재하지 않는 행을 찾을 수 있습니다.

아래 쿼리는 customer_id가 고객 테이블의 어떤 행과도 일치하지 않는 주문 행을 찾아냅니다. 이는 참조 무결성이 깨졌다는 신호입니다.

-- 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
);

빠른 확인

EXISTS와 NOT EXISTS에 대해 이해한 내용을 확인해 보세요.

학습 내용 정리

이 레슨에서는 값을 직접 비교하지 않고도 관련 행의 존재 여부를 확인할 수 있도록 EXISTS와 NOT EXISTS를 사용하는 방법을 배웠습니다.

핵심 내용:

  • EXISTS는 서브쿼리에서 일치하는 행을 하나 찾는 즉시 TRUE를 반환합니다(단락 평가).
  • NOT EXISTS는 서브쿼리에서 일치하는 행을 찾지 못하면 TRUE를 반환합니다.
  • EXISTS 내부에서는 SELECT 1을 사용하세요. 반환되는 값은 중요하지 않습니다.
  • NOT EXISTS는 NULL을 안전하게 처리하지만 NOT IN은 그렇지 않습니다. NULL이 나타날 수 있다면 NOT EXISTS를 우선 사용하세요.
  • EXISTS는 SELECT, UPDATE, DELETE 문에서 사용할 수 있습니다.
  • 존재 여부만 필요하다면 EXISTS가 JOIN보다 더 간결하고 빠른 경우가 많습니다.

자주 묻는 질문

“EXISTS와 NOT EXISTS” 강의는 무료인가요?

네 — “EXISTS와 NOT EXISTS” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 SQL Academy 강의 전체를 잠금 해제할 수 있습니다. SQL Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“EXISTS와 NOT EXISTS”에서 뭘 배우나요?

관련 행이 있는지 효율적으로 확인합니다. 브라우저에서 직접 실행하는 실습 코드로 SQL Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

SQL Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 SQL Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“EXISTS와 NOT EXISTS” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 SQL Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 SQL Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 상관 서브쿼리
  2. EXISTS와 NOT EXISTS
  3. IN과 ANY와 ALL 비교
  4. EXISTS와 JOIN 성능 비교
← SQL Academy(으)로 돌아가기