서브쿼리
쉽게 말하면
서브쿼리는 질문 안에 들어 있는 작은 질문이에요. '평균보다 급여가 높은 사원'을 찾으려면 먼저 평균을 구해야 하죠. 괄호 안에 평균을 구하는 SELECT를 넣고, 그 답으로 바깥 SELECT가 사원을 골라요. 답이 한 줄인지 여러 줄인지에 따라 함께 쓰는 연산자가 달라져요.
시험용 정의
서브쿼리는 SQL 문 안에 괄호로 넣은 또 하나의 SELECT 문이다. 돌려주는 행 수에 따라 단일행(=, > 등과 함께), 다중행(IN, ANY, ALL, EXISTS), 다중 열 서브쿼리로 나눈다. 바깥 쿼리의 열을 참조하면 연관(상관) 서브쿼리다. 놓이는 위치에 따라 SELECT 절의 스칼라 서브쿼리, FROM 절의 인라인 뷰, WHERE·HAVING 절의 서브쿼리가 있다.
비유로 이해하기
"우리 반 평균보다 키 큰 사람"을 찾으려면 먼저 평균을 구하고(안쪽 질문), 그 답으로 다시 고른다(바깥 질문). 안쪽 질문이 서브쿼리다.
자세히
먼저 알아 둘 말
| 말 | 뜻 |
|---|---|
| 메인쿼리 | 서브쿼리를 품고 있는 바깥쪽 SELECT |
| 단일행 연산자 | =, <>, >, <, >=, <= : 값 하나와 비교 |
| 다중행 연산자 | IN, ANY(SOME), ALL, EXISTS : 여러 값과 비교 |
| 스칼라 | 값 하나(1행 1열) |
다중행 연산자
| 연산자 | 뜻 | 예 (30번 급여: 5000, 3000, 2800, 2600) |
|---|---|---|
| IN | 목록 중 하나와 같다 | sal IN (…) → 그 네 값 중 하나 |
| > ANY | 목록 중 하나보다라도 크다 = 최솟값보다 크다 | > 2600 |
| > ALL | 목록의 모든 값보다 크다 = 최댓값보다 크다 | > 5000 |
| < ANY / < ALL | 최댓값보다 작다 / 최솟값보다 작다 | < 5000 / < 2600 |
| EXISTS | 서브쿼리 결과가 한 행이라도 있으면 참 | 값이 아니라 존재 여부만 본다 |
위치별 서브쿼리
| 위치 | 이름 | 특징 |
|---|---|---|
| SELECT 절 | 스칼라 서브쿼리 | 반드시 1행 1열. 0행이면 NULL, 2행 이상이면 오류 |
| FROM 절 | 인라인 뷰 | 결과를 테이블처럼 쓴다. 별칭을 붙여 쓴다. 이 안에서는 ORDER BY도 쓸 수 있다 |
| WHERE·HAVING 절 | 중첩 서브쿼리 | 조건 값을 만든다. HAVING에서는 그룹 비교에 쓴다 |
연관 서브쿼리
서브쿼리 안에서 바깥 쿼리의 열을 쓰면 연관 서브쿼리다. 바깥 행마다 서브쿼리가 다시 계산된다.
예: 자기 부서 평균보다 급여가 많은 사원 SELECT ename FROM emp e WHERE sal > (SELECT AVG(sal) FROM emp WHERE deptno = e.deptno). 서브쿼리의 e.deptno가 바깥 행의 부서다.
서브쿼리 안에서는 바깥 열을 쓸 수 있지만, 바깥 쿼리는 서브쿼리 안의 열을 쓸 수 없다. 서브쿼리의 결과를 바깥에서 보려면 FROM 절 인라인 뷰나 조인을 쓴다.
시험에 이렇게 나와요
- 단일행 연산자에 여러 행 서브쿼리 → 오류
- ANY·ALL 의미 (> ANY = 최솟값보다 큼, > ALL = 최댓값보다 큼)
- EXISTS·NOT EXISTS, NOT IN 서브쿼리 결과에 NULL이 있으면 0행
- 연관 서브쿼리 결과 계산
- 스칼라 서브쿼리(1행 1열), 인라인 뷰(ORDER BY 가능), 서브쿼리 위치별 이름
출제 범위·공식 안내 기반
확인 문제
Q1. WHERE sal = (SELECT sal FROM emp WHERE deptno = 20)을 실행하면? (20번 부서는 5명)
- 결과가 없다
- 오류가 난다
- 첫 번째 값으로만 비교한다
- 20번 부서 사원과 급여가 같은 사원이 나온다
정답 보기
2번 오류가 난다
= 는 값 하나와 비교하는 단일행 연산자인데 서브쿼리가 여러 행을 돌려줘 오류(ORA-01427)다. 여러 행이면 IN, ANY, ALL 같은 다중행 연산자를 써야 한다.
Q2. 서브쿼리가 (2600, 2800, 3000)을 돌려줄 때 sal < ANY (…)와 같은 조건은?
- sal < 3000
- sal IN (2600, 2800, 3000)
- sal < 2800
- sal < 2600
정답 보기
1번 sal < 3000
< ANY는 어느 하나보다만 작으면 되므로 최댓값 3000보다 작다.
Q3. MGR 열에 NULL이 있는 EMP에서 SELECT ename FROM emp WHERE empno NOT IN (SELECT mgr FROM emp)의 결과는?
- 결과 없음
- 관리자인 사원
- 오류
- 관리자가 아닌 사원
정답 보기
1번 결과 없음
NOT IN 목록에 NULL이 있으면 <> NULL이 항상 알 수 없음이라 0행. WHERE mgr IS NOT NULL을 서브쿼리에 넣거나 NOT EXISTS를 쓴다.
Q4. SELECT 절에 쓰여 반드시 한 행 한 열을 돌려줘야 하는 서브쿼리는?
- 인라인 뷰
- 다중 열 서브쿼리
- 다중행 서브쿼리
- 스칼라 서브쿼리
정답 보기
4번 스칼라 서브쿼리
스칼라 서브쿼리. 결과가 없으면 NULL, 두 행 이상이면 오류.
Q5. 서브쿼리에 대한 설명으로 틀린 것은?
- 메인쿼리는 서브쿼리 안의 열을 자유롭게 SELECT할 수 있다
- 서브쿼리는 괄호로 감싼다
- 연관 서브쿼리는 바깥 쿼리의 열을 참조한다
- FROM 절 서브쿼리를 인라인 뷰라고 한다
정답 보기
1번 메인쿼리는 서브쿼리 안의 열을 자유롭게 SELECT할 수 있다
바깥에서는 WHERE 서브쿼리 안의 열을 볼 수 없다. 인라인 뷰로 만들면 볼 수 있다.
헷갈리기 쉬운 O·X
EXISTS 서브쿼리는 SELECT 목록에 무엇을 쓰든 결과가 같다.
정답 보기
O 행이 있는지만 보므로 SELECT 1, SELECT * 모두 같다.
> ALL (서브쿼리)는 서브쿼리 결과의 최솟값보다 크다는 뜻이다.
정답 보기
X 모든 값보다 커야 하므로 최댓값보다 크다.
인라인 뷰 안에서는 ORDER BY를 쓸 수 있다.
정답 보기
O Top N 쿼리에서 정렬한 인라인 뷰에 ROWNUM을 거는 식으로 쓴다.