서브쿼리(subquery)
def: sql문 실행에 필요한 데이터를 추가로 조회하기 안에 sql문 내부에 사용하는 select문
예시
-- 마치 변수를 사용하는 것 같다 SELECT * FROM EMP WHERE SAL > (SELECT SAL FROM EMP WHERE ENAME = 'JONES') -- 함수를 사용한 단일행 서브쿼리문 SELECT E.EMPNO, E.ENAME, E.SAL, D.DEPTNO FROM EMP E, DEPT D WHERE E.DEPTNO = D.DEPTNO -- join조건문 AND E.DEPTNO = 20 AND E.SAL > (SELECT AVG(SAL) FROM EMP);
다중행 서브쿼리
- 다중행 서브쿼리(multi-row subquery)는 실행 결과 값이 여러 개로 나오는 서브쿼리이다.
IN 연산자
-- 원래 in 연산자, 부서번호가 20 또는 30인 사원 정보 출력 SELECT * FROM EMP WHERE DEPTNO IN(20,30); -- 각 부서별 최고 급여를 받는 사원 정보 출력 SELECT * FROM EMP WHERE SAL IN (SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO)
ANY, SOME 연산자
서브쿼리가 반환한 여러 결과 값 중 메인쿼리와 조건식을 사용한 결과가 하나라도 true이면 메인쿼리 조건식을 true로 반환해주는 연산자.
-- 등가연산자(=)와 함께 사용하는 경우 IN과 같은 기능 수행 SELECT * FROM EMP WHERE SAL = ANY (SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO); -- 대소비교연산자 사용. 부서번호 30의 sal 최대값보다 작은 sal을 받는 사원 정보를 출력 SELECT * FROM EMP WHERE SAL < ANY(SELECT SAL FROM EMP WHERE DEPTNO = 30);
ALL 연산자
ANY와 다르게 서브쿼리의 모든 결과가 조건식에 맞아떨어져야 메인커리의 조건식이 true가 되는 연산자.
-- 부서번호가 30인 sal의 최솟값보다 작은 경우 SELECT * FROM EMP WHERE SAL < ALL (SELECT SAL FROM EMP WHERE DEPTNO = 30);
EXISTS 연산자
서브쿼리에 결과 값이 하나 이상 존재하면 조건식이 모두 true, 존재하지 않으면 false가 되는 연산자.
-- 존재하지 않는 경우 아무 것도 출력하지 않는다. SELECT * FROM EMP WHERE EXISTS (SELECT DNAME FROM DEPT WHERE DEPTNO = 50); -- 서브쿼리 결과값이 존재하므로 emp 모든 행을 출력한다. SELECT * FROM EMP WHERE EXISTS (SELECT DNAME FROM DEPT WHERE DEPTNO = 10);
그 외 서브쿼리
비교할 열이 여러 개인 다중열 서브쿼리
메인쿼리에 비교할 열을 괄호로 묶어 명시하고 서브쿼리에서는 괄호로 묶은 데이터와 같은 자료형 데이터를 명시한다.
-- 비교하는 열이 sal과 deptno 2개 SELECT * FROM EMP WHERE (DEPTNO, SAL) IN (SELECT DEPTNO, MAX(SAL) FROM EMP GROUP BY DEPTNO)
FROM 절에서 사용하는 서브쿼리
-- 인라인뷰(inline view). 일부 데이터를 먼저 추출한 다음 별칭을 붙여 사용 SELECT E10.EMPNO, E10.ENAME, E10.DEPTNO, D.DNAME, D.LOC FROM (SELECT * FROM EMP WHERE DEPTNO = 10) E10, (SELECT * FROM DEPT) D WHERE E10.DEPTNO = D.DEPTNO;
from절에 너무 많은 서브쿼리를 지정하면 가독성이 떨어져 with절을 사용하기도 한다.
SELECT 절에 사용하는 서브쿼리
-- 스칼라 서브쿼리(scalar subquery) SELECT EMPNO, ENAME, JOB, SAL, (SELECT GRADE FROM SALGRADE WHERE E.SAL BETWEEN LOSAL AND HISAL) AS SALGRADE, DEPTNO, (SELECT DNAME FROM DEPT WHERE E.DEPTNO = DEPT.DEPTNO) AS DNAME FROM EMP E;