MySQL에서 한 테이블의 데이터 중 다른 테이블에는 존재하지 않는 레코드를 찾아야 하는 경우가 자주 있습니다. 이럴 때 서브쿼리(subquery)와 NOT IN 연산자를 활용하면 간단하게 해결할 수 있습니다. 아래 예제를 통해 단계별로 살펴보겠습니다.
1. 첫 번째 테이블 생성하기
먼저 CREATE 명령어를 사용해 'PresentHistory'라는 이름의 테이블을 생성합니다. 이 테이블은 두 개의 컬럼을 가지고 있습니다.
mysql> CREATE table PresentHistory -> ( -> HisID int, -> HisName varchar(100) -> ); Query OK, 0 rows affected (0.54 sec)
2. 첫 번째 테이블에 데이터 삽입
테이블 생성 후 INSERT 명령어를 사용해 두 번째 테이블에도 존재할 레코드들을 삽입합니다.
mysql> INSERT into PresentHistory values(1,'John'); Query OK, 1 row affected (0.13 sec) mysql> INSERT into PresentHistory values(2,'Bob'); Query OK, 1 row affected (0.15 sec)
데이터가 정상적으로 입력되었는지 SELECT 문으로 확인해 보겠습니다.
mysql> SELECT * from PresentHistory;
위 쿼리를 실행하면 다음과 같은 결과를 얻을 수 있습니다.
+-------+---------+ | HisID | HisName | +-------+---------+ | 1 | John | | 2 | Bob | +-------+---------+ 2 rows in set (0.00 sec)
3. 두 번째 테이블 생성 및 데이터 삽입
이번에는 CREATE 명령어로 'PastHistory'라는 두 번째 테이블을 만듭니다. 역시 두 개의 컬럼으로 구성됩니다.
mysql> CREATE table PastHistory -> ( -> PastId int, -> PastName varchar(100) -> ); Query OK, 0 rows affected (0.74 sec)
테이블을 만든 뒤, 첫 번째 테이블에도 존재하는 레코드 2개와 존재하지 않는 레코드 2개를 함께 삽입합니다.
mysql> INSERT into PastHistory values(1,'John'); Query OK, 1 row affected (0.13 sec) mysql> INSERT into PastHistory values(2,'Bob'); Query OK, 1 row affected (0.13 sec) mysql> INSERT into PastHistory values(3,'Carol'); Query OK, 1 row affected (0.17 sec) mysql> INSERT into PastHistory values(4,'Jason'); Query OK, 1 row affected (0.16 sec)
현재 두 번째 테이블에는 총 4개의 레코드가 있으며, 그중 2개는 첫 번째 테이블과 동일하고 나머지 2개는 첫 번째 테이블에 없는 데이터입니다. SELECT 문으로 확인해 보겠습니다.
mysql> SELECT * from PastHistory;
실행 결과는 다음과 같습니다.
+--------+----------+ | PastId | PastName | +--------+----------+ | 1 | John | | 2 | Bob | | 3 | Carol | | 4 | Jason | +--------+----------+ 4 rows in set (0.00 sec)
4. NOT IN 서브쿼리로 차집합 구하기
한 테이블에는 없지만 다른 테이블에는 존재하는 레코드를 조회하는 기본 문법은 다음과 같습니다.
SELECT * from yourSecondTableName where columnNamefromSecondtable NOT IN (SELECT columnNamefromfirsttable from yourFirstTableName);
이 문법을 실제 예제에 적용하여, 두 번째 테이블(PastHistory) 중 첫 번째 테이블(PresentHistory)에 없는 고유한 레코드만 조회해 보겠습니다.
mysql> SELECT * from PastHistory where PastName not in (select HisName from PresentHistory);
위 쿼리의 실행 결과는 다음과 같습니다.
+--------+----------+ | PastId | PastName | +--------+----------+ | 3 | Carol | | 4 | Jason | +--------+----------+ 2 rows in set (0.00 sec)
결과 분석
출력 결과를 보면 'Carol'과 'Jason'이라는 두 개의 레코드가 반환되었습니다. 이는 첫 번째 테이블인 PresentHistory에는 존재하지 않고 오직 PastHistory 테이블에만 있는 데이터입니다. 이처럼 NOT IN 연산자와 서브쿼리를 조합하면 두 테이블 간의 차집합을 손쉽게 구할 수 있습니다.
참고: 대량의 데이터를 다룰 때는 NOT IN보다 LEFT JOIN ... IS NULL 방식이나 NOT EXISTS 절을 사용하는 것이 성능 면에서 더 유리할 수 있습니다. 상황에 맞게 적절한 방법을 선택하시기 바랍니다.