일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- ifnull
- 감정은 습관이다
- 백엔드
- 빠르게 실패하기
- five lines challenge
- LAG
- 지도학습
- nvl2
- Batch Normalization
- beautifulsoup
- 데이터 전처리
- 오차 행렬
- 웹서비스 기획
- NULLIF
- DecisionTree
- 비지도학습
- CASE WHEN
- 정밀도
- 강화학습
- SQL
- Normalization
- 데이터 프로젝트
- sorted
- 평가 지표
- 결정트리
- 재현율
- layer normalization
- recall
- NVL
- 데이터 분석
- Today
- Total
Day to_day
[MySQL] NOT IN을 사용할 때 주의할 점 (+ EXISTS와 비교하기) 본문
리트코드에서 나온 문제 중에 쉽게 사용해왔던 NOT IN을 사용하면서 겪었던 문제를 함께 공유하려고 한다.
지시 사항
Each node in the tree can be one of three types:
- "Leaf": if the node is a leaf node.
- "Root": if the node is the root of the tree.
- "Inner": If the node is neither a leaf node nor a root node.
Write an SQL query to report the type of each node in the tree.
Return the result table in any order.
정답 코드
SELECT id,
(CASE
WHEN (T.p_id IS Null) THEN "Root"
WHEN T.id NOT IN (SELECT p_id FROM Tree WHERE p_id IS NOT NULL) THEN "Leaf"
ELSE "Inner"
END) AS type
FROM Tree T;
해설
이 문제를 해결하기 위해서는 케이스를 나눠서 코드를 작성해줘야 한다.
경우의 수는 다음과 같다.
- p_id가 null인 경우 : 부모 노드가 없다는 의미. 그래서 null이 맨 꼭대기에 위치하는 부모 노드 "Root"
- p_id에 값이 있고, 다른 노드의 p_id가 되기도 하는 경우 : 부모도 있고, 자식 노드도 있다는 의미. 이 경우 "Inner"로 생각
- p_id에 값이 있지만, 다른 노드의 p_id가 아닌 경우 : 부모는 있지만 자식이 없는 제일 끝단에 위치. 이 경우는 "Leaf"라고 생각
처음 시도
SELECT id,
(CASE
WHEN (T.p_id IS Null) THEN "Root"
WHEN T.id NOT IN (SELECT p_id FROM Tree) THEN "Leaf"
ELSE "Inner"
END) AS type
FROM Tree T;
<출력 결과>
“Leaf” 케이스에 대해서 잘 작동하지 않는 것 같다
NOT IN이 어떻게 반환되는지 먼저 알아야겠다.
NOT IN을 사용하면 어떻게 반환될까?
먼저 id에 1, 2가 들어있지 않은 경우를 알고 싶어서 select절에 바로 때려 넣어봤다.
그랬더니 1과 2는 0으로 나오고, 1과 2가 아닌 경우는 1이 나온다.
SELECT (id NOT IN (1,2)) AS NOT_IN
FROM Tree;
그러면 NOT IN 안에 null값이 포함되면 어떨까?
SELECT id, (id NOT IN (1,2, null)) AS NOT_IN
FROM Tree;
신기하게도 null 값만 포함시켰는데 3,4,5는 null값이 아님에도 불구하고 1이 반환되지 않고 null값이 반환되는 것을 볼 수 있다.
NOT IN 연산자의 특징
NOT IN 연산자는! = (같지 않다)와 같다.
IN ( ' A' , ' B ' ) : A or B : A와 B 가 포함되는 데이터만 추출
반대로 NOT IN ( 'A' , 'B') : not A and not B : A와 B 가 포함되지 않는 데이터만 추출
결과적으로 null이 포함되면 결과값 자체가 null이 반환되게 된다.
그래서 NOT IN 앞에 서브 쿼리로 WHERE IS NOT NULL 조건을 붙여서 해결해 주었다.
EXISTS 활용해 보기
IN과 비슷한 EXISTS를 한번 사용해서 해결해볼 수도 있을 것 같다.
EXISTS는 IN과 비슷하게 활용된다.
EXISTS는 주로 WHERE절에서 조건에 따라 데이터를 걸러내서 결과를 조회하는 기능을 하는데 IN과 비슷하게 결과 값은 0 또는 1을 반환한다.
0 : 존재하지 않을 경우.
1 : 값이 존재할 경우.
이 문제에서 SELECT 절에서 사용하여 어떻게 반환되는지 확인해 보자면
SELECT *, EXISTS (SELECT * FROM Tree T2 WHERE T1.id = T2.p_id) AS exist
FROM Tree T1;
Tree 테이블에서 id에 있는 값과 p_id의 값 전체를 비교해서 있는 경우 1, 없는 경우 0을 반환한다.
<실행 결과>
그러면 NOT IN을 사용했던 것처럼 이를 이용하여 EXISTS값이 0이 나오는 경우 “Leaf”라고 지칭할 수 있겠다.
EXISTS와 IN의 차이는 무엇일까?
IN의 경우,
테이블의 모든 칼럼 값을 직접 비교하기 때문에 대량의 데이터를 조회하는 경우
속도가 급격하게 느려지게 된다.
이에 반해
EXISTS는 해당 값이 TRUE/FALSE냐 만을 비교하기 때문에
대량의 데이터 조회 시 IN보다 훨씬 빠르다
또한
IN은 NULL을 인식하지 못해서 NVL(오라클), IFNULL(MySQL)
등으로 처리를 해 줘야 하지만 EXISTS는 처리를 하지 않아도 된다는 특징이 있다
결론적으로
조회하는 데이터가 많지 않을 경우(몇백~몇천) - IN
조회하는 데이터가 그보다 많을 경우 - EXISTS
매우 빠른 속도가 필요할 경우 - INNER JOIN
REF
[MSSQL] IN 연산자 사용법 (NOT IN, 서브쿼리)
SQL IN EXISTS JOIN 성능 비교 및 용도 정리글
'SQL' 카테고리의 다른 글
[MySQL] 결과 값 제한하기 - LIMIT 활용하기 (0) | 2023.02.07 |
---|---|
[MySQL] 날짜 연산 DATE_ADD, DATE_SUB, DATEDIFF (+ LEAD, LAG) (0) | 2023.01.03 |
WITH 절 사용하기 (feat. PARTITION BY) (0) | 2022.11.04 |
재귀 쿼리 WITH RECURSIVE (0) | 2022.11.04 |
CASE WHEN 사용하기 (0) | 2022.11.02 |