[MySQL]0.EXIST, IN

jaegoo1199·2021년 5월 8일
1

DBMS

목록 보기
1/1
post-thumbnail

안녕하세요. 조재구입니다. 이번 시간에는 이번학기 수업을 듣고 있는 데이터베이스 개론에서 SQL 관련 과제를 하던중 EXISTIN의 작동방식이 살짝 난해하다는 생각이 들어 정리를 해보려고 합니다.

Data Setting


가장 먼저 FILM_CUSTOMER TABLE입니다.

+-------------+---------+
| customer_id | film_id |
+-------------+---------+
|           0 |       0 |
|           1 |       1 |
|        NULL |       2 |
|           5 |       3 |
|           7 |       4 |
|           8 |       5 |
+-------------+---------+

다음은 RENTAL_CUSTOMER TABLE입니다.

+-------------+-----------+
| customer_id | rental_id |
+-------------+-----------+
|           0 |        0  |
|           1 |        1  |
|        NULL |        2  |
|           3 |        3  |
|           4 |        4  |
|           5 |        5  |
+-------------+-----------+

IN


IN에서 가장 두드러지는 특징은 서브쿼리에서 미리 데이터를 가져온 다음 그 데이터를 바탕으로 조건에 맞는 데이터를 출력합니다. 다음의 SQL 쿼리를 보겠습니다.

SELECT * 
FROM FILM_CUSTOMER f 
WHERE f.cutomer_id IN (SELECT r.customer_id FROM RENTAL_CUSTOMER)

위의 SQL이 작동하는 과정은 다음과 같습니다.
1. SELECT r.customer_id FROM RENTAL_CUSTOMER이 먼저 실행되어 관련 데이터가 추출됩니다.
2. 추출된 데이터 [0, 1, 2, 3, 4, 5, NULL]를 바탕으로 상위 쿼리를 실행합니다.
3. 결과는 다음과 같습니다.

+-------------+---------+
| customer_id | film_id |
+-------------+---------+
|           0 |       0 |
|           1 |       1 |
|           5 |       3 |
|           7 |       4 |
|           8 |       5 |
+-------------+---------+

NOT IN


기본적인 연산의 방향은 IN과 매우 유사합니다. 하지만 NOT을 판단하는 과정이 다소 직관과 멀게 느껴지는 경우가 있습니다. 다음을 보겠습니다.

SELECT * 
FROM FILM_CUSTOMER f 
WHERE f.cutomer_id NOT IN (SELECT r.customer_id FROM RENTAL_CUSTOMER)

먼저 실행 결과부터 확인하겠습니다.

+-------------+---------+
| customer_id | film_id |
+-------------+---------+
|           0 |       0 |
|           1 |       1 |
+-------------+---------+

위의 쿼리를 조금 변형시키면 다음과 같습니다.

SELECT * 
FROM FILM_CUSTOMER f 
WHERE f.cutomer_id NOT IN (1, 2, 3, 4, 5, NULL)

이제부터 차근차근 NOT IN이 작동하는 방식을 보겠습니다. NOT IN은 직관적으로 "포함하지 않는다"의 의미를 가지고 있습니다. 이를 쿼리는 다음과 같은 방식으로 해석합니다.

SELECT * 
FROM FILM_CUSTOMER f
WHERE f.number != 1 AND
      f.number != 2 AND
      f.number != 3 AND
      f.number != 4 AND 
      f.number != 5 AND 
      f.number != NULL;

여기서 우리가 눈여겨 봐야할 계산은 바로 NULL과의 연산입니다. 익히 알다싶이 NULL과의 계산은 UNKNOW을 반환하며 이 값은 TRUE/FALSE도 아닌 값입니다. 따라서 우리가 직관적을 생각하는 5이상의 수인 6, 7, 8 모두 결과값에 포함되지 않은 것입니다.

이렇듯 NULL의 경우는 쿼리계산에서 우리의 직관과는 상대적으로 다른 결과값을 유발할 수 있기 때문에 되도록 제약을 걸어서 자용하는 것이 좋으며 IS NULL을 사용하여 NULL의 문제를 어느정도는 해결할 수 있습니다.

EXISTS


EXISTSIN과는 다소 반대로 동작합니다. 먼저 쿼리부터 살펴보겠습니다.

SELECT * 
FROM FILM_CUSTOMER f
WHERE EXISTS (SELECT r.customer_id FROM RENTAL_CUSTOMER r)

위의 쿼리가 작동하는 방식은 다음과 같습니다.
1. 먼저 상위 쿼리인 FILM_CUSTOMER에 접근을 하여 관련된 데이터를 가져옵니다.
2. 이후에 가져온 데이터를 하나씩 가져오고 서브쿼리에 대한 계산 결과가 존재하는지를 확인합니다.

위의 쿼리를 실행한 결과값은 다음과 같습니다.

+-------------+-----------+
| customer_id | rental_id |
+-------------+-----------+
|           0 |        0  |
|           1 |        1  |
|        NULL |        2  |
|           3 |        3  |
|           4 |        4  |
|           5 |        5  |
+-------------+-----------+

즉, 상위 쿼리에서 계산한 값들을 하나씩 가져와 서브쿼리의 계산결과가 존재하는지 확인하는 과정에서 실제로 계산 과정에서 서브쿼리와의 연관성은 존재하지 않음과 동시에 서브쿼리는 무조건 결과값을 반환합니다. 이로인해서 결과값이 FILM_CUSTOMER 전체가 되는 것입니다.

이를 직관적으로 우리가 유도하는 데이터를 얻기 위해서는 상위쿼리와 서브쿼리의 연관성을 넣어주면 됩니다.

SELECT * 
FROM FILM_CUSTOMER f
WHERE EXISTS (
    SELECT r.customer_id F
    ROM RENTAL_CUSTOMER r
    WHERE f.customer_id = r.customer_id
)

결과값은 다음과 같습니다.

+-------------+-----------+
| customer_id | rental_id |
+-------------+-----------+
|           0 |        0  |
|           1 |        1  |
|           3 |        3  |
+-------------+-----------+

NOT EXISTS


위의 모든 내용을 따라오셨다면, NOT EXISTS를 이해하는데 큰 어려움은 없을 겁니다. 기본적인 과정은 EXISTS와 동일합니다.

SELECT * 
FROM FILM_CUSTOMER f
WHERE NOT EXISTS (
    SELECT r.customer_id F
    ROM RENTAL_CUSTOMER r
    WHERE f.customer_id = r.customer_id
)

위의 결과는 다음과 같습니다.

+-------------+---------+
| customer_id | film_id |
+-------------+---------+
|        NULL |       2 |
|           7 |       4 |
|           8 |       5 |
+-------------+---------+

NULL과의 계산은 항상 UNKNOWN을 반환합니다. 이로인해서 (NULL, 2)의 값이 서브쿼리와 아무런 결과값을 만들어내지 않기 때문에 NOT EXISTS에 해당이 되어 위와 같은 결과값을 출력하는 것입니다.


Reference

profile
아직 거북이지만 곧 앞질러 갈겁니다.

0개의 댓글