S E P H ' S

[MySQL] #1 IN / EXISTS / NOT IN / NOT EXISTS 본문

Programing & Coding/MySQL

[MySQL] #1 IN / EXISTS / NOT IN / NOT EXISTS

yoseph0310 2021. 4. 6. 22:05

먼저 포스트를 작성하기 위해 작성한 DB Table의 정보이다.

 

<그림1-1> customer Table
<그림1-2> customer 테이블
<그림2-1> customer_order
<그림2-2> customer_order 테이블

  IN / EXISTS 는 서브쿼리를 반환하기 위한 연산자이다. 하지만 두 연산자는 수행 매커니즘이 다르다. 다음을 보면 두 연산자의 매커니즘의 차이를 이해하는데 도움이 될 것이다.

 

1. select ( 1 != null ) || 2<3;

 

2. select ( 1 != null ) || 2>3;
3. select ( 1 != null ) && 2>3;
4. select ( 1 != null ) && 2<3;

<그림3> 1번 SQL 수행결과
<그림4> 2번 SQL 수행결과
<그림5> 3번 SQL 수행결과
<그림6> 4번 SQL 수행결과

  각 SQL 문의 수행결과를 보고 알 수 있는 것은 SQL문이 null과 연산을 할 때, 1,3번과 같이  확정적인 연산 결과는 false, true (0,1)를 반환하지만 결과를 알 수 없는 확정적이지 않은 연산 결과는 NULL을 반환 한다는 것이다. 

 

IN

in은 in 다음에 오는 쿼리가 먼저 수행된다.

select 	customer_name
  from 	customer
 where 	customer_id in (select customer_id from customer_order);

  즉 위의 SQL문은 "select customer_id from customer_order" 을 먼저 수행하고 그 결과 값으로 customer_name을 조회하게 된다.

<그림7> in 안의 SQL 실행결과

  in 안의 SQL은 2, 2, null을 반환하고

select 	customer_name
  from 	customer
 where 	customer_id in (2,2,null);

위의 SQL과 동일한 것이다. 위의 결과는 다음 <그림8>과 같다. 이러한 in은 or 연산과 매커니즘이 동일하다.

 

<그림8> 실행결과

 

 

NOT IN

 

다음의 NOT IN을 포함한 SQL문을 수행해보면 본문을 시작하면서 설명했던 것들과 함께 이해가 잘 될 것이다.

select 	customer_name
  from 	customer
 where 	customer_id not in (select customer_id from customer_order);

  in이 쿼리 결과를 포함하는 결과를 반환했다면 not in 은 말그대로 포함하지 않은 결과를 반환하는 것이다. 하지만 위의 SQL문을 실행하면 다음과 같은 결과가 나온다.

<그림9>

  결과값이 아무것도 없는 것을 볼 수 있다. in 내부의 쿼리를 실행하면

select 	customer_name
  from 	customer
 where 	customer_id not in (2,2,null);

   이와 같은 결과일 것이고 이 요소들과 일치하지 않아야 결과로 반환될 것이다. 하지만 (1 != null)과 같이 null과 연산을 하는 부분에서 결과가 확정적이지 않은 연산이기 때문에 null을 반환하고 아무것도 출력되지 않는 것이다. 이를 수정하려면 다음과 같이 SQL문을 작성하면 된다.

select 	customer_name
  from 	customer
 where 	customer_id not in (select customer_id from customer_order
	where customer_id is not null);

<그림10> 성공적으로 2를 제외한 결과

 

EXISTS / NOT EXISTS

 

  이런 매커니즘의 차이 외에도 속도면에서도 exists 연산자가 in보다 우수하여 더 많이 사용한다. in이 in () 내부의 SQL부터 수행했다면 exists는 바깥쪽의 SQL을 먼저 수행하고, 수행된 결과에 대해서 각각 exists 절을 모두 수행한다. 이러한 exists 절은 내부적으로 join 매커니즘을 수행한다.

 

select 	c.customer_name
  from 	customer c
 where 	exists (
		select o.customer_id from customer_order o
        	 where c.customer_id = o.customer_id
        );

<그림11>

 

select 	c.customer_name
  from 	customer c
 where 	not exists (
		select o.customer_id from customer_order o
        	 where c.customer_id = o.customer_id
        );

<그림12>

   NOT EXISTS가 별다른 처리 없이 <그림12>와 같이 결과를 내는 이유는 null 인부분에 대해서 

"select  c.customer_name from  customer c where = null;" 과 같이 수행되는데 not exists 바깥의 SQL 결과에 대해서 각각 처리가 되므로 null과 연산이 된 부분은 제외하고 결과가 반환이 되는 것이다.