JINWOOJUNG

[ DB ] 데이터베이스...7(SQL...3) 본문

Database

[ DB ] 데이터베이스...7(SQL...3)

Jinu_01 2024. 10. 12. 02:15
728x90
반응형

본 포스팅은 인하대학교 최원익교수님의 "데이터베이스설계" 수업에서 진행한 프론트, 백엔드 실습 관련 정리하는 포스팅입니다. 백엔드, 프론트엔드는 전문 분야가 아니기에 공부용으로 올리는 포스팅이며 오류사항이 있을 수 있습니다.

 

https://jinwoo-jung.tistory.com/105

 

[ DB ] 데이터베이스...6(SQL...2)

본 포스팅은 인하대학교 최원익교수님의 "데이터베이스설계" 수업에서 진행한 프론트, 백엔드 실습 관련 정리하는 포스팅입니다. 백엔드, 프론트엔드는 전문 분야가 아니기에 공부용으로 올리

jinwoo-jung.com

 


 

지난 포스팅과 이어서 진행되며, 현재 t1, t2 Table의 Tuples는 다음과 같다.

 

이전 포스팅에서 배운 Join 연산은 Table 간의 관계라고 표현할 수 있다. 지금부터 배우는 In 조건의 경우 일종의 Filtering이다.

 

In 조건

In 조건은 여러 값을 OR 관계로 묶어 나열하는 조건을 WHERE <Condition>에 사용할 때 사용되는 조건문이다.

 

예를들어, Id가 1이거나 2인 것을 조건문으로 쓰면 WHERE Id = 1 OR Id = 2라고 표현할 수 있다. 이때, In 조건을 사용하면, WHERE Id IN (1,2)로 표현할 수 있다. 따라서 IN 뒤에 나오는 ()을 먼저 실행하고, () 안에 Id가 있는 Tuples을 Filtering 한다고 해석하는 것이 더 이해하기 쉬울 것이다. 

 

  • select * from t1 where id in ( select id from t2 )

()안을 먼저 해석하면, t2 Table로부터 가져온 id이다. 따라서 t2 Table의 id에 있는 id를 가지는 t1 Table의 모든 Column을 반환하라는 의미이다. 

 

 

select * from t1, t2 where t1.id = t2.id 로 실행한 결과는 아래와 같다. Equi Join의 결과인데, 확실히 Table 간의 관계를 나타내기에 t1, t2 Table의 정보가 모두 나타나고 이는 In 조건과는 차이가 있음을 확인할 수 있다.  

 

  • select * from t1 where id not in ( select id from t2 )

NOT IN 조건의 경우 IN 조건과 반대로 ()안에 없는 경우를 반환한다. 즉, t2 Table의 id에 있는 id를 가지지 않는 t1 Table의 모든 Column을 반환하라는 의미이다. 

 

  • select * from t1 where id not in ( select id from t2 where id is not null)

In 조건인 ()내에 WHERE <Condition>을 통해 부가적인 조건을 추가할 수 있다. 단순히 t2 Table의 id에 없는지 Filtering 하는 것이 아닌, t2 Table의 id 중 NULL이 아닌 id에 대하여 Filtering을 진행한다. 

 

NULL이 있는 상황을 구현하기 위해 t2 Table에 id = NULL, title = "noname1_2"인 Tuple을 추가하였다.

NOT IN 조건 내의 WHERE에 의해 t2 Table에 id가 NULL이 아닌 값들 중, t1 Table에 id가 없는 경우는 id = 3, 4이므로 오른쪽 아래 결과 나온다. 

 

만약 현 상태에서 select * from t1 where id not in ( select id from t2 ) 를 수행하면 어떻게 될까?

 

음.. 생각지 못한 결과이다. id가 3, 4인 경우는 {1,2,6,NULL}에 포함되지 않기에 앞선 select * from t1 where id not in ( select id from t2 where id is not null)와 동일한 결과가 도출될 줄 알았지만 Empty이다. 이를 이해하기 위해서는 NULL에 대하여 조금 자세히 공부해야 한다. 

 


 

NULL

 

NULL은 True도 아니고 False도 아니고 그저 NULL이다. 

 

다음과 같은 쿼리의 결과를 예측 해 보자. 이때, 1은 True, 0은 False를 의미한다.

1 IS TRUE 1 IS FALSE 0 IS TRUE 0 IS FALSE
1 0 0 1

 

그러면, NULL을 비교해 보면 어떻게 될까?

NULL IS TRUE NULL IS FALSE
0 0

 

NULL IS TRUE가 0이므로 NULL은 FALSE 일 것 같지만, NULL IS FALSE이므로 FALSE도 아니다. 그러면 NULL은 0일까? 아니면 NULL은 NULL과의 연산은 가능할까?

NULL = 0 NULL <> 0 NULL = NULL NULL <> NULL
NULL NULL NULL NULL

 

전부 아니다. NULL은 알 수 없는 값이다. 그렇기에 0, 다른 숫자, True, False 무엇과도 비교할 수 없으며, NULL 값 끼리도 서로 알 수 없는 값이기에 그 결과 역시 알 수 없다. 

 


따라서, NULL 값은 어떠한 값과도 비교 및 연산을 할 수가 없다. 그래서 NULL과의 비교 연산에서는 FALSE를 반환한다. 

 

그렇다면, 다시 In 조건을 살펴보자. In 조건은 ()안이 OR로 묶일 때 사용된다고 하였다.

 

select * from t1 where id in ( select id from t2 ) 는 결국 t1.id = 1 or t1.id = 2 or t1.id = 6 or t1.id = NULL으로 해석된다. 따라서 t1.id = NULL은 항상 False를 반환하지만,  t1.id = 1 or t1.id = 2 or t1.id = 6 에서 하나라도 True이면 or 이기에 True가 되서 반환된다. 

 

하지만, select * from t1 where id not in ( select id from t2 ) 은 다른 문제이다. 집합을 공부할 때 드 모르간 법칙을 생각하면 되는데, NOT ( t1.id = 1 or t1.id = 2 or t1.id = 6 or t1.id = NULL) => t1.id != 1 and t1.id != 2 and t1.id != 6 and t1.id != NULL으로 해석된다. 하지만, NULL의 비교연산은 항상 False를 반환하므로 결국 Empty가 반환되는 것이다. 여기서 중요한 한가지 공식이 나오는데, NOT IN 조건에서 ()안에 NULL이 포함되면 항상 Empty가 반환된다.

 

EXISTS 연산자

EXISTS는 EXISTS 뒤에오는 ()내 서브 쿼리의 결과가 존재하는지 확인하는 연산자입니다. IN 조건과 달리 메인 쿼리가 먼저 실행되고 서브 쿼리가 실행됩니다.

 

  • select * from t1 where exists ( select * from t2 )

여기서 메인 쿼리는 select * from t1, 서브 쿼리는 EXISTS 연산자 뒤에오는 ()내의 select * from t2이다. 즉, t1 Table의 모든 Column 중에서 서브 쿼리가 True인 것만 반환되는데, 여기서 select * from t2 이므로 t2 Table에 1개의 Tuple이 있으면 True이다. 따라서 t1 Table이 모두 반환 될 것이다. 

 

 

  • select * from t1 where exists ( select * from t2 where t1.id = t2.id )

서브 쿼리에 추가적인 조건을 부여하였다. t1 Table의 모든 Column에 대하여, t1.id = t2.id가 같은 것만 True로 반환된다. 

 

  • select * from t1 where not exists ( select * from t2 where t1.id = t2.id )

not exists의 경우 서브 쿼리를 만족하지 않는 경우 즉, False인 경우 반환된다. 직관적으로 t1 Table에서 id가 3, 4인 Tuples가 반환 될 것 같으며, 3=NULL 비교의 경우 False이기에 정상적으로 반환 될 것이라고 예측할 수 있다. 

 

그렇다면 t1 Table에도 NULL이 있으면 어떻게 될까?

 

 

위와 같이 두 Table 모두에 NULL을 가지는 Tuple이 존재하는 상황이다. 

 

t1 Table의 id가 NULL인 경우를 살펴보자. t2 Table에도 id = NULL이 존재하지만, NULL = NULL은 UNKNOWN으로 처리된다. 따라서 EXISTS 서브 쿼리는 결과를 반환하지 않으므로 NOT EXISTS는 참으로 평가된다. 

 

t2 테이블에도 **id = NULL**이 존재하지만, **NULL = NULL 비교는 TRUE가 아니고 UNKNOWN**으로 처리됩니다. 따라서 EXISTS 서브쿼리는 결과를 반환하지 않으며, **NOT EXISTS는 참(TRUE)**으로 평가됩니다. 그래서 **t1.id = NULL**인 행도 반환됩니다.

 

 

 

 

 

 

 

Reference

https://velog.io/@park2348190/SQL-IN-쿼리에서-Null-값의-영향

https://m.blog.naver.com/schatz37/221731866770

728x90
반응형