- 메인 쿼리(MAIN QUERY)에 포함하는 하위 쿼리(SUB QUERY)
- 서브쿼리는 메인쿼리에 괄호()를 이용해서 포함시킨다.
- 항상 서브쿼리를 먼저 실행하고, 서브쿼리 실행 결과를 메인쿼리에서 사용한다.
SELECT
절 : 스칼라 서브쿼리FROM
절 : 인라인뷰WHERE
절 : 서브쿼리
- 단일 행 서브쿼리
- 서브쿼리 결과가 1개
- PK나 UNIQUE 칼럼의 동등 비교(=) 결과, 함수의 결과
- 단일 행 연산자를 사용(
=
,!=
,>
,>=
,<
,<=
)
- 다중 행 서브쿼리
- 서브쿼리 결과가 2개 이상
FROM
절,WHERE
절에서 사용- 다중행 연산자를 사용 (
IN
,ANY
,ALL
등)
사원번호가 1001인 사원과 같은 직급(POSITION)을 가진 사원 조회하기
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM EMPLOYEE
WHERE POSITION = (SELECT POSITION -- 단일 행 서브쿼리이므로 연산자 =를 사용, 하위쿼리는 메인쿼리와 동등비교(=)되므로 반드시 POSITION을 반환
FROM EMPLOYEE
WHERE EMP_NO = 1001); -- EMP_NO는 PK이므로 단일 행 서브쿼리
급여(SALARY)가 가장 높은 사원 조회하기
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM EMPLOYEE
WHERE SALARY = (SELECT MAX(SALARY)
FROM EMPLOYEE); -- 서브쿼리가 함수이므로 단일 행 서브쿼리
부서번호가 1인 부서와 같은 지역에 있는 부서 정보를 조회하기
SELECT DEPT_NO, DEPT_NAME, LOCATION
FROM DEPARTMENT
WHERE LOCATION = (SELECT LOCATION
FROM DEPARTMENT
WHERE DEPT_NO = 1);
평균급여 이상을 받는 사원 조회하기
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM EMPLOYEE
WHERE SALARY >= (SELECT AVG(SALARY)
FROM EMPLOYEE); -- 서브쿼리가 함수이므로 단일 행 서브쿼리
평균근속기간 이상을 근무한 사원 조회하기
일수 계산 : SYSDATE - HIRE_DATE
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM EMPLOYEE
WHERE (SYSDATE - HIRE_DATE) >= (SELECT AVG(SYSDATE - HIRE_DATE)
FROM EMPLOYEE);
개월 계산 : MONTHS_BETWEEN(SYSDATE, HIRE_DATE)
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM EMPLOYEE
WHERE MONTHS_BETWEEN(SYSDATE, HIRE_DATE) >= (SELECT AVG(MONTHS_BETWEEN(SYSDATE, HIRE_DATE))
FROM EMPLOYEE);
부서번호가 2인 부서에 근무하는 사원들의 직급과 일치하는 직급을 가진 사원 조회하기
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM EMPLOYEE
WHERE POSITION IN(SELECT POSITION -- 다중행 서브쿼리의 동등 비교는 IN 연산으로 수행해야 한다.
FROM EMPLOYEE
WHERE DEPART = 2); -- DEPART가 PK/UNIQUE가 아니기 때문에 다중 행 서브쿼리
TIP! 단일 행/다중 행 상관 없이 동등 비교는 IN 연산으로 수행 가능하다.
부서명이 '영업부'인 부서에 근무하는 사원 조회하기
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM EMPLOYEE
WHERE DEPART IN(SELECT DEPT_NO
FROM DEPARTMENT
WHERE DEPT_NAME = '영업부'); -- DEPT_NAME가 PK/UNIQUE가 아니기 때문에 다중 행 서브쿼리
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM DEPARTMENT D INNER JOIN EMPLOYEE E
ON D.DEPT_NO = E.DEPART
WHERE DEPT_NAME = '영업부';
직급이 '과장'인 사원들이 근무하는 부서 조회하기
SELECT DEPT_NO, DEPT_NAME, LOCATION
FROM DEPARTMENT
WHERE DEPT_NO IN(SELECT DEPART
FROM EMPLOYEE
WHERE POSITION = '과장'); -- POSITION가 PK/UNIQUE가 아니기 때문에 다중 행 서브쿼리
SELECT DEPT_NO, DEPT_NAME, LOCATION
FROM DEPARTMENT D INNER JOIN EMPLOYEE E
ON D.DEPT_NO = E.DEPART
WHERE POSITION = '과장';
부서번호가 1인 부서에 근무하는 사원들의 급여보다 더 많은 받는 급여를 받는 사원 조회하기
- 어떤 급여(2000000, 5000000)이든 하나의 급여보다 많이 받으면 조회하기
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM EMPLOYEE
WHERE SALARY > ANY(SELECT SALARY
FROM EMPLOYEE
WHERE DEPART = 1); -- DEPART가 PK/UNIQUE가 아니기 때문에 다중 행 서브쿼리
WHERE SALARY > ANY(2000000, 5000000)
SALARY가 2000000보다 크거나, 5000000보다 크면 된다. (OR
개념)
따라서 최소급여 2000000보다 크면 만족하는 상황이다.
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM EMPLOYEE
WHERE SALARY > (SELECT MIN(SALARY)
FROM EMPLOYEE
WHERE DEPART = 1); -- 서브쿼리가 함수이므로 단일 행 서브쿼리
부서번호가 1인 부서에 근무하는 사원들의 급여보다 더 많은 받는 급여를 받는 사원 조회하기
- 모든 급여(2000000, 5000000)와 비교해서 많이 받으면 조회하기
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM EMPLOYEE
WHERE SALARY > ALL(SELECT SALARY
FROM EMPLOYEE
WHERE DEPART = 1); -- DEPART가 PK/UNIQUE가 아니기 때문에 다중 행 서브쿼리
WHERE SALARY > ALL(2000000, 5000000)
SALARY가 2000000보다 크고, 5000000보다 크면 된다. (AND
개념)
따라서 최대급여 5000000보다 크면 만족하는 상황이다.
SELECT EMP_NO, NAME, DEPART, GENDER, POSITION, HIRE_DATE, SALARY
FROM EMPLOYEE
WHERE SALARY > (SELECT MAX(SALARY)
FROM EMPLOYEE
WHERE DEPART = 1); -- 서브쿼리가 함수이므로 단일 행 서브쿼리
전체 사원의 인원수, 급여합계/평균/최대/최소 조회하기
SELECT
(SELECT COUNT(*) FROM EMPLOYEE)
, (SELECT SUM(SALARY) FROM EMPLOYEE)
, (SELECT AVG(SALARY) FROM EMPLOYEE)
, (SELECT MAX(SALARY) FROM EMPLOYEE)
, (SELECT MIN(SALARY) FROM EMPLOYEE)
FROM
DUAL;
부서번호가 1인 부서와 같은 지역에서 근무하는 사원 조회하기
- 사원번호(EMP_NO), 사원명(NAME), 부서번호(DEPART), 부서명(DEPT_NAME) 조회
SELECT E.EMP_NO, E.NAME, E.DEPART, D.DEPT_NAME
FROM EMPLOYEE E INNER JOIN DEPARTMENT D
ON D.DEPT_NO = E.DEPART
WHERE D.LOCATION = (SELECT LOCATION
FROM DEPARTMENT
WHERE DEPT_NO = 1); -- 기본키의 동등비교는 단일행으로만 표시
스칼라 서브쿼리는 일치하지 않는 정보를 NULL로 처리
한다.
따라서 스칼라 서브쿼리와 동일한 방식의 조인은 외부조인
이다.
SELECT
E.EMP_NO
, E.NAME
, E.DEPART
, (SELECT D.DEPT_NAME
FROM DEPARTMENT D
WHERE D.DEPT_NO = E.DEPART
AND D.DEPT_NO = 1)
FROM
EMPLOYEE E;
조인 접근
SELECT E.EMP_NO, E.NAME, E.DEPART, D.DEPT_NAME
FROM DEPARTMENT D RIGHT OUTER JOIN EMPLOYEE E
ON D.DEPT_NO = E.DEPART
WHERE D.LOCATION = (SELECT LOCATION
FROM DEPARTMENT
WHERE DEPT_NO = 1);
서브쿼리
를 의미SELECT A.EMP_NO, A.NAME, A.POSITION
FROM (SELECT EMP_NO, NAME, POSITION -- 인라인뷰가 조회한 칼럼만 작성가능
FROM EMPLOYEE
WHERE DEPART = 1) A; -- 인라인뷰의 별명은 A