IN 연산자
IN 연산자는 특정 값이 지정한 리스트(또는 서브쿼리 결과) 내에 존재하는지 확인하는 데 사용된다.
SELECT * FROM orders o WHERE o.customer_id IN (1, 2);
동작 방식
-
IN구문은 내부적으로OR연산자로 변환되어 실행된다.SELECT * FROM orders o WHERE (o.customer_id = 1 OR o.customer_id = 2); -
따라서 리스트에 포함된 값들 중 하나라도 일치하면 해당 행이 조회된다.
서브쿼리를 사용하는 경우
SELECT * FROM orders o
WHERE o.customer_id IN (SELECT c.customer_id FROM customers c);
- 서브쿼리를 먼저 실행하여
customer_id목록을 가져온다. orders테이블에서 한 행씩 가져와customer_id값이 서브쿼리 결과 중 하나라도 일치하면 출력한다.- 이 과정은
orders테이블의 모든 행에 대해 반복된다.
NULL 값이 포함된 경우
IN 연산자를 사용할 때 서브쿼리 결과에 NULL 값이 포함되어 있으면 주의해야 한다. 예를 들어, customers 테이블의 customer_id 값이 (1, 2, 3, 4, NULL)이라면 다음과 같은 동작이 발생한다.
orders테이블의customer_id값이NULL일 경우, 서브쿼리 결과에NULL이 포함되어 있어도IN조건에서 비교 연산이UNKNOWN(즉,FALSE)이 되어 해당 행은 출력되지 않는다.- 이는 MySQL에서
NULL값이 포함된 비교 연산은 항상FALSE를 반환하기 때문이다.
NOT IN 연산자
NOT IN 연산자는 특정 값이 지정한 리스트(또는 서브쿼리 결과)에 존재하지 않는 경우를 필터링하는 데 사용된다.
not in 구문의 경우 and 연산자로 변경된다는 차이점이 있다.
SELECT * FROM orders o
WHERE o.customer_id NOT IN (SELECT c.customer_id FROM customers c);
NULL 값이 포함된 경우 문제 발생
- 서브쿼리 결과가
(1, 2, 3, 4, NULL)이면,NOT IN연산자가customer_id = 5인 데이터를 비교할 때 문제 발생 customer_id = 5와1, 2, 3, 4비교 결과는TRUE지만,5 != NULL비교 결과는UNKNOWN(즉,FALSE)AND연산자로 묶이므로 최종 결과는FALSE, 따라서customer_id = 5데이터도 출력되지 않음
NULL 문제 해결 방법
SELECT * FROM orders o
WHERE o.customer_id NOT IN (SELECT c.customer_id FROM customers c WHERE c.customer_id IS NOT NULL);
IS NOT NULL조건을 추가하면NULL값을 제외하고 비교 가능
NULL 비교 연산의 주의점
= NULL또는<> NULL은 MySQL에서FALSE를 반환한다. 따라서IS NULL또는IS NOT NULL을 반드시 사용해야 한다.IN또는NOT IN연산을 사용할 때NULL값이 포함되어 있으면 결과가 예상과 다를 수 있기에 주의!
EXISTS 연산자
EXISTS는 서브쿼리에서 한 개 이상의 결과가 존재하는 경우 TRUE를 반환하며, 존재하지 않으면 FALSE를 반환한다.
SELECT * FROM orders o
WHERE EXISTS (
SELECT c.customer_id FROM customers c
WHERE c.customer_id = o.customer_id
);
동작 방식
orders테이블의 각 행에 대해 서브쿼리를 실행한다.- 서브쿼리가 한 개 이상의 행을 반환하면
TRUE를 반환하여 해당 행을 출력한다. EXISTS는 서브쿼리에서 한 개의 행이라도 찾으면 즉시TRUE를 반환하므로, 불필요한 검색을 줄일 수 있다.
EXISTS vs. IN 차이점
EXISTS는 서브쿼리에서 해당하는 값을 찾으면 즉시 종료하므로, 서브쿼리의 결과 크기가 클수록 성능이 유리하다.- 반면,
IN연산자는 서브쿼리의 모든 결과를 가져와서 비교해야 하므로 성능이 떨어질 수 있다.
NULL 값이 포함된 경우
EXISTS 연산자는 NULL 값이 포함된 경우에도 정상적으로 동작한다.
SELECT * FROM orders o
WHERE EXISTS (
SELECT c.customer_id FROM customers c
WHERE c.customer_id = o.customer_id OR c.customer_id IS NULL
);
EXISTS연산자는 단순히 서브쿼리 결과가 있는지 확인하는 역할을 하기 때문에NULL값이 포함되어 있어도 문제가 되지 않는다.- 위 쿼리에서는
customers.customer_id가NULL인 경우에도 결과가 존재하면TRUE를 반환하여 해당 행이 출력 된다.
그러나 NULL을 제외하고 비교하고 싶다면 다음과 같이 IS NOT NULL 조건을 추가할 수 있다.
SELECT * FROM orders o
WHERE EXISTS (
SELECT c.customer_id FROM customers c
WHERE c.customer_id = o.customer_id AND c.customer_id IS NOT NULL
);
이렇게 하면 customers 테이블에 NULL 값이 있어도 EXISTS 연산자의 비교에서 제외된다.
NOT EXISTS 연산자
동작 방식
NOT EXISTS는 서브쿼리 결과가 존재하지 않는 경우TRUE를 반환하여 해당 행을 출력함.- 서브쿼리 결과가 하나라도 존재하면
FALSE를 반환하여 해당 행을 제외함.
SELECT * FROM orders o
WHERE NOT EXISTS (
SELECT 1 FROM customers c
WHERE c.customer_id = o.customer_id
);
orders테이블에서customer_id가customers테이블에 존재하지 않는 경우만 반환됨.
NULL 값이 포함된 경우의 동작
NOT EXISTS는NULL값이 포함된 서브쿼리에서도 정상적으로 동작함.IN이나NOT IN과 달리NULL값으로 인해 결과가UNKNOWN(즉,FALSE)이 되는 문제가 없음.
SELECT * FROM orders o
WHERE NOT EXISTS (
SELECT 1 FROM customers c
WHERE c.customer_id = o.customer_id
);
orders.customer_id가NULL인 경우에도 정상적으로 비교됨.customers.customer_id에NULL값이 있어도NOT EXISTS는 단순히 서브쿼리가 결과를 반환하는지만 확인하므로 문제 발생하지 않음.
NULL 값을 제외하는 방법
NULL값을 제외하고 비교하려면IS NOT NULL을 추가해야 함.
SELECT * FROM orders o
WHERE NOT EXISTS (
SELECT 1 FROM customers c
WHERE c.customer_id = o.customer_id AND c.customer_id IS NOT NULL
);
- 이렇게 하면
customers.customer_id가NULL인 경우 비교 대상에서 제외됨.
Start the conversation