학생 테이블
학번 | 이름 | 학년 |
---|---|---|
1111 | 홍길동 | 1 |
2222 | 임꺽정 | 2 |
3333 | 유관순 | 3 |
4444 | 안중근 | 3 |
5555 | 홍범도 | 4 |
IN
구문에 입력된 값들 중에서 하나라도 일치하는 것이 있으면 조회된다.
즉, 쿼리가 실행될 때 내부적으로 or 연산자로 변경되어 실행되는 것이다.
IN
구문은 IN
연산자에 다른 SELECT
문을 넣을 수 있다.(=서브쿼리)
대량의 값을 대입하거나, 동적으로 값이 변경되어야 할 때 IN
연산자에 서브쿼리를 사용할 수 있다.
SELECT * FROM 학생 WHERE 학년 IN (3, 4);
# or 연산자로 변환된 쿼리
SELECT * FROM 학생 WHERE (학년 = 3 OR 학년 = 4);
MySQL 5.6에서 서브쿼리가 대폭 개선되었으며, MySQL 5.5까지는 서브쿼리의 최적화 성능이 좋지 않아
JOIN
으로 전환하여 실행되는 것이 좋다. MySQL 5.6는 서브쿼리 사용 시 내부적으로JOIN
으로 실행된다.
Q. 학생 테이블에서 학년이 3인 학생들의 학번을 선택
SELECT * FROM 학생
WHERE 학번 IN (SELECT 학번 FROM 학생 WHERE 학년 = 3);
IN
구문의 경우 서브쿼리의 결과로 나온 값들 중 일치하는 값이 하나라도 있으면 되지만, NOT IN
을 사용할 경우 서브쿼리의 결과로 나온 모든 값들과 일치하지 않는지를 체크하게 된다.
즉, IN
구문의 경우 내부적으로 or 연산자로 변경되었다면, NOT IN
구문의 경우 and 연산자로 변경된다.
Q. 학생 테이블에서 학년이 3이 아닌 학생들의 학번을 선택
SELECT * FROM 학생
WHERE 학번 NOT IN (SELECT 학번 FROM 학생 WHERE 학년 = 3);
EXISTS
구문에서는 IN
구문과는 다르게 메인 쿼리에 먼저 접근하여 값을 가져오고, EXISTS
의 서브쿼리를 실행시켜 결과가 존재하는지를 판단한다.
IN
연산자는 비교할 값을 직접 대입할 수 있지만, EXISTS
연산자는 서브쿼리만 사용할 수 있다는 특징이 있다.
IN
: 서브쿼리 → 메인쿼리 → 도출EXISTS
: 메인쿼리 → 서브쿼리 → 도출서브쿼리의 결과가 true인지 false인지 체크하기 때문에 결과가 존재할 경우(=true) 메인 쿼리의 결과를 출력한다.
Q. "학년"이 특정 학년보다 높은 학생을 선택
SELECT * FROM 학생 s
WHERE EXISTS (SELECT 1 FROM 학생 WHERE 학년 > 2 AND 학번 = s.학번);
NOT EXISTS
에서는 서브쿼리 내의 결과가 존재하지 않을 경우(=false) 메인 쿼리의 결과를 출력한다.
1개의 SQL 문장 내에서 먼저 A라는 질문의 답을 구하고, 이 값을 B라는 질문의 조건으로 사용하여 최종적인 값을 도출해야 하는 경우가 있다. 이 때 사용하는 것이 서브쿼리이다.
예)
SELECT 컬럼이름A, 컬럼이름B, ...
FROM 테이블이름
WHERE 조건연산자 (서브쿼리);
SELECT 컬럼이름A, 컬럼이름B, ...
FROM 테이블이름
WHERE 조건연산자 (SELECT X FROM 테이블이름 WHERE 조건);
ORDER BY
사용 불가