본문 바로가기
CS/DB

IN / EXISTS / 상관 서브쿼리

by 넬준 2021. 12. 4.

IN

 

열명 IN (집합)


스칼라 값은 = 연산자로 비교가 가능하다.
하지만 비교대상이 집합인 경우에는 = 연산자를 사용할 수가 없기 때문에
IN 키워드를 사용하여 집합 내에 해당 값이 존재하는지 비교할 수 있다.
집합 내에 해당 값이 존재하면 참이다. 여러 OR 조건문을 하나의 식으로 쓴 것이다.


IN 왼쪽에는 하나의 열만 지정되기 때문에 집합은 집합 패턴 1, 2의 경우만 가능하다.

예)

table1

no name
1 aa
2 bb
3 cc
4 dd
5 NULL


table2

no name
1 가가
2 나나
3 다다

 

SELECT * FROM table1 WHERE table1.no IN (SELECT table2.no FROM table2);


결과)

no name
1 aa
2 bb
3 cc


먼저 table2에 접근한다.
IN 구의 서브쿼리 먼저 실행하여 해당 집합을 반환한다.
그리고 나서, table1 요소에서 하나씩 가져와 IN 이하 집합의 요소들과 비교하는 과정을 거친다.
만일 table1.no가 IN 이하 집합의 요소와 같은 값이 있다면 참인 행이 된다.
(WHERE 구는 행을 검색)

NULL 처리

IN에서는 집합에 NULL이 있어도 무시하지 않는다.
하지만 = 비교연산자로 각 값들을 비교하므로,
IS NULL을 사용해야하는 NULL 비교는 할 수 없다.
NULL = NULL로는 원하는 값을 얻을 수 없다.
(MySQL 같은 경우에는 집합에 NULL이 포함된 경우,
왼쪽 값이 집합에 있는 경우 참, 집합에 없는 경우 NULL을 반환한다.
NULL반환은 비교할 수 없다는 의미이다.
원하는 결과를 얻으려면 추가 설정을 해줘야 한다.)

EXISTS


IN 키워드와 비슷하게 특정 집합에 데이터의 존재 여부를 판별하기 위해 EXISTS를 쓸 수 있다.


예) IN과 같은 예시

SELECT * FROM table1 WHERE EXISTS (SELECT table2.no FROM table2);


위의 결과는 IN에서의 예시와 같은 결과값이 나올까?

결과)

no name
1 aa
2 bb
3 cc
4 dd
5 NULL


답은 아니다.

먼저 IN 구문에서 처리 방식을 다시 보자.
제일 먼저 서브쿼리 구문을 처리하고,
그 결과 반환되는 집합요소를 가지고 주쿼리 요소와 하나씩 비교하면서 참/거짓을 판별했다.

EXISTS 구문에서는 처리 방식이 다르다.
먼저 table1에 접근하여 하나의 데이터를 가져온다.
데이터를 가지고 EXISTS 구문의 서브쿼리를 실행한다.
서브쿼리를 실행한 뒤 반환값이 하나라도 있다면 참으로 판별한다.

다시 위 EXISTS가 포함된 명령을 보자.
table1에서 맨 처음에 [no : 1 / name : aa]라는 데이터를 가지고,
EXISTS 뒤 서브쿼리인 ( SELECT table2.no FROM table2 )을 실행하고 반환값이 있는지 확인한다.
반환값이 있으므로 해당 데이터는 참으로 판별한다.
즉, WHERE 절에 의해 참으로 판별되어 출력가능한 데이터가 된다.
사실, 서브쿼리인 ( SELECT table2.no FROM table2 )는 table1의 데이터 값에 상관없이
항상 결과값을 하나 이상 반환하는 쿼리이므로, table1의 모든 데이터가 출력되는 결과값이 나온 것이다.

그럼 IN에서와 같은 결과값을 갖기 위해서는 어떻게 쿼리문을 작성해야 할까?

SELECT * FROM table1 WHERE EXISTS (SELECT * FROM table2 WHERE table1.no = table2.no);


결과 )

no name
1 aa
2 bb
3 cc


위와 같이 작성하면, table1의 no값 중에서 table2의 no값과 같은 경우에만
EXISTS 이하 서브쿼리문에서 값을 반환하여 참으로 판별할 수 있다.

IN / EXISTS를 사용하여 같은 결과값을 얻었지만 내부 처리 과정은 완전히 다르다는 것을 기억해야 한다.

NOT IN / NOT EXISTS

IN / EXISTS의 부정문으로
NOT IN은 반환된 집합에 해당 요소가 없는 경우 참,
NOT EXISTS는 반환되는 행이 하나도 없을 시 참이다.


상관 서브쿼리

위 EXISTS가 포함된 마지막 쿼리문을 보자.

SELECT * FROM table1 WHERE EXISTS (SELECT * FROM table2 WHERE table1.no = table2.no);


부모 쿼리와 자식인 서브쿼리가 특정 관계를 갖고 있는 경우 해당 서브쿼리를 상관 서브쿼리라 부른다.
즉, 서브 쿼리가 부모 쿼리의 어떤 것이라도 참조하고 있는 경우를 말한다.
여기서는 서브쿼리가 부모 쿼리의 no 컬럼을 참조하고 있다.
상관 서브쿼리는 단독으로 쿼리를 실행할 수 없다.

SELECT * FROM table1 WHERE table1.no IN (SELECT table2.no FROM table2);


반대로, 위와 같이 부모 쿼리와 관련없는 서브쿼리를 비상관 서브쿼리라 부른다.
비상관 서브쿼리는 부모와 독립적으로 작동하므로, 단독으로 쿼리를 실행할 수 있다.






참조

https://doorbw.tistory.com/222

'CS > DB' 카테고리의 다른 글

테이블 생성 / 삭제 / 변경  (0) 2021.12.04
데이터베이스 계층 구조  (0) 2021.12.04
서브쿼리  (0) 2021.12.03
그룹화 - GROUP BY  (0) 2021.12.03
집계함수 - COUNT / SUM / AVG / MIN / MAX  (0) 2021.12.03

댓글