서브쿼리가 0행인 세 부서는 오류 없이 NULL 이다. 바깥 DEPT 4행은 그대로 남는다. INNER JOIN 이었다면 짝이 없는 부서는 빠진다.
MAX처럼 집계를 쓰면 빈 집합에서도 1행(값 NULL)이 나온다. 결과는 같은 NULL 이지만, COUNT는 0 을 돌려준다는 점이 다르다(W4 Day 1).
한 부서에 사원이 여럿이면 ENAME 을 하나로 고를 수 없다.
SELECT D.DNAME, (SELECT ENAME FROM EMP E WHERE E.DEPTNO = D.DEPTNO) AS ENAME FROM DEPT D;
SELECT D.DNAME, (SELECT ENAME FROM EMP E WHERE E.DEPTNO = D.DEPTNO) AS ENAME FROM DEPT D *ERROR at line 1:ORA-01427: single-row subquery returns more than one row
열을 둘 돌려줘도 값 하나 자리에 넣을 수 없다. 급여 5000 이상은 KING 한 명이라 행은 1행이지만 열이 2개다.
SELECT D.DNAME, (SELECT ENAME, SAL FROM EMP E WHERE E.DEPTNO = D.DEPTNO AND E.SAL >= 5000) AS X FROM DEPT D;
SELECT D.DNAME, (SELECT ENAME, SAL FROM EMP E WHERE E.DEPTNO = D.DEPTNO AND E.SAL >= 5000) AS X FROM DEPT D *ERROR at line 1:ORA-00913: too many values
⚠️ 함정: 스칼라 서브쿼리 결과가 0행이면 오류가 아니라 NULL 이다. 오류는 2행 이상(ORA-01427)이거나 2열 이상(ORA-00913)일 때만 난다.
FROM 절에 넣은 서브쿼리를 인라인 뷰(Inline View) 라 부른다. 실행 결과가 그 자리에서 임시 테이블처럼 쓰인다. 부서별 평균을 인라인 뷰로 만들고 EMP 와 조인한다.
SELECT E.ENAME, E.SAL, A.AVG_SAL FROM EMP E, (SELECT DEPTNO, ROUND(AVG(SAL)) AS AVG_SAL FROM EMP GROUP BY DEPTNO) A WHERE E.DEPTNO = A.DEPTNO AND E.SAL > A.AVG_SAL ORDER BY E.ENAME;
WITH는 인라인 뷰를 문장 앞으로 꺼내 이름을 붙인다. 위의 인라인 뷰 조인을 WITH 로 다시 쓴 것이다.
WITH DEPT_AVG AS (SELECT DEPTNO, ROUND(AVG(SAL)) AS AVG_SAL FROM EMP GROUP BY DEPTNO) SELECT E.ENAME, E.SAL, A.AVG_SAL FROM EMP E JOIN DEPT_AVG A ON E.DEPTNO = A.DEPTNO WHERE E.SAL > A.AVG_SAL ORDER BY E.ENAME;
스칼라 서브쿼리 : 값 하나 자리에 쓰는 한 행 한 열 서브쿼리. 결과가 없으면 NULL 이다.
인라인 뷰 : FROM 절에 쓴 서브쿼리. 그 문장 안에서 임시 테이블처럼 쓰인다.
뷰(VIEW) : SELECT 문에 이름을 붙여 저장한 가상 테이블. 데이터는 저장하지 않는다.
독립성·편리성·보안성 : 뷰의 세 가지 장점. 구조 변경 흡수, 복잡한 쿼리 단순화, 열·행 숨김.
WITH 절 : 서브쿼리에 이름을 붙여 문장 앞에 정의하는 표기. CTE 라고도 한다.
ORA-00904 : 그 자리에서 보이지 않는 열 이름이나 별칭을 썼을 때의 오류(invalid identifier).
📝 연습 문제
선택지를 클릭하면 정답·해설이 펼쳐집니다.
문제 1
부서별 최고 급여는 10번 5000(KING), 20번 3000(FORD·SCOTT), 30번 2850(BLAKE)이다. 다음 SQL 의 결과 행 수는?
```sql
SELECT E.ENAME FROM EMP E WHERE E.SAL = (SELECT MAX(SAL) FROM EMP S WHERE S.DEPTNO = E.DEPTNO);
```
문제 2
DEPT 는 4개 부서이고 10·20·30번 부서에는 사원이 여러 명 있다. 다음 SQL 을 Oracle 에서 실행한 결과로 알맞은 것은?
```sql
SELECT D.DNAME, (SELECT ENAME FROM EMP E WHERE E.DEPTNO = D.DEPTNO) FROM DEPT D;
```
문제 3
DEPT 40(OPERATIONS)에는 사원이 없다. 다음 SQL 의 결과에 대한 설명으로 알맞은 것은?
```sql
SELECT D.DNAME, (SELECT MAX(SAL) FROM EMP E WHERE E.DEPTNO = D.DEPTNO) AS MAX_SAL FROM DEPT D;
```