SELECT ENAME, SAL FROM EMP WHERE SAL = (SELECT MAX(SAL) FROM EMP WHERE DEPTNO = 30);
ENAME SAL---------- ----------BLAKE 2850
MAX를 빼면 서브쿼리가 30번 부서 6명의 급여 6행을 돌려준다. =는 값 하나와만 비교할 수 있다.
SELECT ENAME, SAL FROM EMP WHERE SAL = (SELECT SAL FROM EMP WHERE DEPTNO = 30);
SELECT ENAME, SAL FROM EMP WHERE SAL = (SELECT SAL FROM EMP WHERE DEPTNO = 30) *ERROR at line 1:ORA-01427: single-row subquery returns more than one row
오류는 실행 중에 결과가 2행 이상으로 나왔을 때 난다. 같은 문장도 데이터가 바뀌어 1행만 나오면 오류가 나지 않는다.
서브쿼리가 0행이면 오류가 아니다. 비교 값이 NULL 이 되어 조건이 참이 되지 않고, 결과는 0행이다.
IN은 서브쿼리가 1행만 돌려줘도 문제없다. 결과가 몇 행일지 모르면 다중행 연산자가 안전하다.
> ALL: 가장 큰 2850 보다 커야 한다. BLAKE 자신(2850)은 2850 > 2850이 거짓이라 빠진다.
같은 자리에 > ANY를 쓰면 가장 작은 950 보다만 크면 된다. 30번 밖에서는 SMITH(800)만 빠진다.
식
같은 뜻
> ANY (목록)
> MIN(목록)
< ANY (목록)
< MAX(목록)
> ALL (목록)
> MAX(목록)
< ALL (목록)
< MIN(목록)
= ANY (목록)
IN (목록)
<> ALL (목록)
NOT IN (목록)
서브쿼리가 0행일 때 두 연산자는 반대로 움직인다. DEPT 40 에는 사원이 없다.
SELECT COUNT(*) FROM EMP WHERE SAL > ALL (SELECT SAL FROM EMP WHERE DEPTNO = 40);SELECT COUNT(*) FROM EMP WHERE SAL > ANY (SELECT SAL FROM EMP WHERE DEPTNO = 40);
COUNT(*)---------- 14 COUNT(*)---------- 0
ALL: 어긋나는 값이 하나도 없으니 참이다. 14행이 모두 나온다.
ANY: 만족하는 값이 하나도 없으니 거짓이다. 그래서 > ALL과 > (SELECT MAX ...)는 서브쿼리가 빌 때만 결과가 다르다. MAX 쪽은 NULL 과 비교해 0행이다.
SELECT ENAME, DEPTNO, JOB FROM EMP WHERE DEPTNO IN (SELECT DEPTNO FROM EMP WHERE ENAME IN ('SMITH', 'ALLEN')) AND JOB IN (SELECT JOB FROM EMP WHERE ENAME IN ('SMITH', 'ALLEN')) ORDER BY DEPTNO, ENAME;
WHERE 절 서브쿼리는 값의 목록을 넘길 뿐이라 순서가 의미가 없다. Oracle 은 여기에 ORDER BY 를 쓰면 문법 오류를 낸다.
SELECT COUNT(*) FROM EMP WHERE DEPTNO IN (SELECT DEPTNO FROM DEPT ORDER BY DEPTNO);
SELECT COUNT(*) FROM EMP WHERE DEPTNO IN (SELECT DEPTNO FROM DEPT ORDER BY DEPTNO) *ERROR at line 1:ORA-00907: missing right parenthesis
오류 문구는 "오른쪽 괄호가 없다"이다. 파서가 ORDER BY 앞에서 괄호가 닫혀야 한다고 보기 때문이다.
FROM 절의 인라인 뷰에는 ORDER BY 를 쓸 수 있다. 정렬한 뒤 ROWNUM으로 앞의 몇 행을 자르는 Top N 쿼리가 이 성질을 쓴다(W6).
위치
ORDER BY
WHERE·HAVING 절 서브쿼리
쓸 수 없다 (ORA-00907)
FROM 절 인라인 뷰
쓸 수 있다
메인쿼리
맨 끝에 한 번
Oracle 12c 부터는 ORDER BY 뒤에 FETCH FIRST n ROWS ONLY 를 붙이면 WHERE 절 서브쿼리에서도 받아 준다. 정렬이 "앞의 n 행" 을 고르는 데 쓰이기 때문이다. 이 노트의 설명과 문항은 FETCH 없이 ORDER BY 만 쓴 경우를 기준으로 한다.
내일은 바깥 행을 참조하는 상관 서브쿼리, SELECT 절의 스칼라 서브쿼리, FROM 절의 인라인 뷰와 뷰를 다룬다.
서브쿼리 : 다른 SQL 문 안에 괄호로 넣은 SELECT 문. 바깥 문장은 메인쿼리라 부른다.
단일행 서브쿼리 : 결과가 0행 또는 1행인 서브쿼리. =·> 같은 단일행 연산자와 쓴다.
다중행 서브쿼리 : 결과가 여러 행일 수 있는 서브쿼리. IN·ANY·ALL·EXISTS와 쓴다.
다중 컬럼 서브쿼리 : 여러 열을 돌려줘 (A, B) IN (...)처럼 쌍으로 비교하는 서브쿼리.
ANY / ALL : 목록 중 하나라도 / 전부 조건을 만족하면 참. 빈 목록에서 ANY 는 거짓, ALL 은 참이다.
EXISTS : 서브쿼리 결과가 1행 이상이면 참. 돌려주는 값은 보지 않는다.
ORA-01427 : 단일행 연산자 뒤 서브쿼리가 2행 이상을 돌려줬을 때의 오류.
ORA-00913 : 비교할 자리보다 서브쿼리가 돌려준 열이 많을 때의 오류(too many values).
📝 연습 문제
선택지를 클릭하면 정답·해설이 펼쳐집니다.
문제 1
EMP 의 30번 부서에는 사원이 6명 있다. 다음 SQL 을 Oracle 에서 실행한 결과로 알맞은 것은?
```sql
SELECT ENAME FROM EMP WHERE SAL = (SELECT SAL FROM EMP WHERE DEPTNO = 30);
```
문제 2
EMP 의 MGR 열에는 KING 의 NULL 이 하나 있고, 부하 직원이 없는 사원은 8명이다. 다음 SQL 의 결과는?
```sql
SELECT COUNT(*) FROM EMP WHERE EMPNO NOT IN (SELECT MGR FROM EMP);
```
문제 3
30번 부서에는 사원이 있다. SAL > ALL (SELECT SAL FROM EMP WHERE DEPTNO = 30) 과 같은 결과를 내는 조건은?
문제 4
다음 중 Oracle 에서 실행하면 오류가 나는 것은?
문제 5
SMITH 는 (20, CLERK), ALLEN 은 (30, SALESMAN)이다. EMP 에서 (20, CLERK)는 2명, (30, SALESMAN)은 4명, (30, CLERK)는 1명이다. 다음 SQL 의 결과는?
```sql
SELECT COUNT(*) FROM EMP WHERE (DEPTNO, JOB) IN (SELECT DEPTNO, JOB FROM EMP WHERE ENAME IN ('SMITH', 'ALLEN'));
```