20241101 D30
<SUBQUERY 서브쿼리>
- 하나의 주된 SQL(SELECT, CREATE, INSERT, UPDATE ...) 안에 포함된 또 하나의 SELECT문
- 메인 SQL문을 보조하기 위해 사용한다.
SELECT문 -> SELECT, FROM, WHERE, HAVING 등 다양한 위치에사용,그때마다 부르는 명칭이 다르다.
- SELECT -> 스칼라 쿼리 -> 하나의 값(스칼라)을 반환해주는 서브쿼리라는 의미.
- FROM -> 인라인 뷰 -> 서브쿼리 조회결과를 테이블처럼 사용할때 사용.
- WHERE, HAVING -> 스칼라 쿼리, 프래디케이트 쿼리 -> 조건검사에 사용되는 서브쿼리.
SELECT EMP_NAME, DEPT_CODE
FROM EMPLOYEE
WHERE DEPT_CODE =(
SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME = '노옹철'
);
SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY > (
SELECT AVG(SALARY)
FROM EMPLOYEE
);
서브쿼리 구문
- 서브쿼리를 수행한 결과값이 몇행 몇열에 따라 분류
- 단일행(단일열) 서브쿼리 : 서브쿼리를 수행 한 결과 값이 1개(스칼라)
- 다중행(단일열) 서브쿼리 : 서브쿼리를 수행 한 결과 값이 여러 행
- (단일행) 다중열 서브쿼리 : 서브쿼리를 수행 한 결과 값이 여러 열
- 다중행 다중열 서브쿼리 : 서브쿼리를 수행 한 결과 값이 여러 행과 열
1. 단일행 (단일열) 서브쿼리 (SINGE ROW SUBQUERY)
- 서브쿼리의 조회 결과 값이 1개인 경우 사용.
- 일반 연사자 사용 가능.(=, !=, <, >)
SELECT EMP_ID, EMP_NAME, JOB_CODE, SALARY, HIRE_DATE
FROM EMPLOYEE
WHERE SALARY = (
SELECT MIN(SALARY)
FROM EMPLOYEE
);
SELECT EMP_ID, EMP_NAME, SALARY, DEPT_TITLE
FROM EMPLOYEE
WHERE EMP_NAME = '노옹철';
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, SALARY
FROM EMPLOYEE
LEFT JOIN DEPARTMENT ON DEPT_CODE = DEPT_ID
WHERE SALARY >= ( SELECT SALARY
FROM EMPLOYEE
WHERE EMP_NAME = '노옹철'
);
SELECT DEPT_CODE, DEPT_TITLE, SUM(SALARY)
FROM EMPLOYEE
LEFT JOIN DEPARTMENT ON DEPT_CODE = DEPT_ID
GROUP BY DEPT_CODE, DEPT_TITLE
HAVING SUM(SALARY ) = (
SELECT MAX (SUM(SALARY))
FROM EMPLOYEE
GROUP BY DEPT_CODE
);
2. 다중행 (단일열) 서브쿼리 (MULTI ROW SUBQUERY)
- 서브쿼리로 조회한 결과값이 여러행인 경우 사용
- IN (10, 20, 30) 서브쿼리
: 여러개의 결과 값 중 하나라도 일치하면 참, 없다면 거짓
- (>, <)ANY (10, 20, 30) 서브쿼리
: 여러개의 결과 값 중 "하나라도" 크거나(>) 작을(<)경우 참/거짓을 반환
- (<, >)ALL (10, 20, 30) 서브쿼리
: 여러개의 결과 값 모두 크거나, 작은 경우 참 / 거짓을 반환
SELECT DEPT_CODE, MAX(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE;
SELECT EMP_NAME, JOB_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY IN ( SELECT MAX(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE);
SELECT EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE = 'D9';
SELECT EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE = 'D6';
SELECT EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE IN (
SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME IN('선동일' ,'유재식')
);
SELECT EMP_NAME, JOB_CODE, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE JOB_CODE IN (
SELECT JOB_CODE
FROM EMPLOYEE
WHERE EMP_NAME IN('하동운', '이오리')
);
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE
AND JOB_NAME = '과장';
SELECT SALARY
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE
AND JOB_NAME = '대리';
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE
AND JOB_NAME = '과장'
AND SALARY <= ANY(SELECT SALARY
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE
AND JOB_NAME = '대리' );
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE
AND JOB_NAME = '과장'
AND SALARY >= ANY(
SELECT SALARY
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE
AND JOB_NAME = '차장'
);
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE E
JOIN JOB J USING(JOB_CODE);
WHERE JOB_NAME = '과장'
AND SALARY >= ALL(SELECT SALARY
FROM EMPLOYEE
JOIN JOB USING(JOB_CODE)
WHERE JOB_NAME = '차장'
);
SELECT EMP_ID, EMP_NAME, MANAGER_ID
FROM EMPLOYEE E1
WHERE EXISTS ( SELECT 1
FROM EMPLOYEE E2
WHERE E1.MANAGER_ID IS NOT NULL
AND E1.EMP_ID = E2.EMP_ID
);
3. (단일행) 다중열 서브쿼리
- 서브쿼리 조회 결과가 한 행이지만, 나열된 컬럼의 갯수가 여러개인 겨우
SELECT DEPT_CODE, JOB_CODE
FROM EMPLOYEE
WHERE EMP_NAME = '하이유';
SELECT EMP_NAME, DEPT_CODE, JOB_CODE, HIRE_DATE
FROM EMPLOYEE
WHERE DEPT_CODE = 'D5' AND JOB_CODE = 'J5';
SELECT EMP_NAME, DEPT_CODE, JOB_CODE, HIRE_DATE
FROM EMPLOYEE
WHERE (DEPT_CODE, JOB_CODE ) = (SELECT DEPT_CODE, JOB_CODE
FROM EMPLOYEE
WHERE EMP_NAME= '하이유' );
SELECT EMP_NAME, DEPT_CODE, MANAGER_ID
FROM EMPLOYEE
WHERE EMP_NAME = '박나라';
SELECT EMP_NAME, JOB_CODE, MANAGER_ID
FROM EMPLOYEE
WHERE (JOB_CODE, MANAGER_ID) = (SELECT JOB_CODE, MANAGER_ID
FROM EMPLOYEE
WHERE EMP_NAME = '박나라'
);
4. 다중행 다중열 서브쿼리
SELECT JOB_CODE, MIN(SALARY)
FROM EMPLOYEE
GROUP BY JOB_CODE;
SELECT EMP_NAME, EMP_ID, JOB_CODE, SALARY
FROM EMPLOYEE
WHERE (JOB_CODE, SALARY) IN (SELECT JOB_CODE, MIN(SALARY)
FROM EMPLOYEE
GROUP BY JOB_CODE
);
SELECT DEPT_CODE, MAX(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE;
SELECT EMP_ID, EMP_NAME, NVL(DEPT_CODE, '없음'), SALARY
FROM EMPLOYEE
WHERE (NVL(DEPT_CODE, 1), SALARY) IN (SELECT NVL(DEPT_CODE, 1) , MAX(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE
)
5. 스칼라 쿼리
- 단일행 단일열 서브쿼리의 일종으로 SELECT절에서 사용되는 서브쿼리를 지칭함.
- SELECT 절이 실행 될때 마다 서브쿼리문이 실행되면서 조회결과 값을 반환함.
- 현재 조회 된 행의 "칼럼값"을 서브쿼리 내부에서 기술 할 수 있다.
- 단점으로는, 매 행 마다 실행되기 때문에 대규모 데이터 처리시 성능이 떨어 질수 있다.
SELECT EMP_ID,
EMP_NAME,
DEPT_TITLE
FROM EMPLOYEE
JOIN DEPARTMENT ON DEPT_CODE = DRPT_ID;
SELECT EMP_ID,
EMP_NAME,
(SELECT DEPT_TITLE FROM DEPARTMENT WHERE DEPT_CODE = DEPT_ID ) 부서명
FROM EMPLOYEE;
SELECT EMP_ID, EMP_NAME, DEPT_CODE
,(SELECT JOB_NAME FROM JOB WHERE JOB_CODE = EMPLOYEE.JOB_CODE) 직급명
FROM EMPLOYEE;
6. 인라인 뷰(INLINE VIEW)
- FROM절에서 사용하는 서브쿼리를 지칭.
- 서브쿼리를 수행한 결과를 테이블 대신에 사용( 파생테이블)
SELECT
EMP_ID,
EMP_NAME,
(SALARY + SALARY * NNL(BONUS, 0)) *12 보너스포함연봉,
DEPT_CODE
FROM EMPLOYEE
WHERE 보너스포함연봉 >= 3000000;
SELECT *
FROM (
SELECT EMP_ID,
EMP_NAME,
(SALARY + SALARY * NVL(BONUS, 0)) * 12 "보너스포함연봉", DEPT_CODE
FROM EMPLOYEE
) E
WHERE 보너스포함연봉 >= 30000000;
SELECT EMP_NAME,
SALARY
FROM EMPLOYEE
ORDER BY SALARY DESC;
SELECT ROWNUM,
EMP_NAME,
SALARY
FROM EMPLOYEE
ORDER BY SALARY DESC;
SELECT ROWNUM, EMP_NAME, SALARY
FROM(
SELECT
EMP_NAME,
SALARY
FROM EMPLOYEE
ORDER BY SALARY DESC
)E
WHERE ROWNUM <= 5;
SELECT DEPT_CODE, ROUND(AVG(SALARY)) 평균급여
FROM EMPLOYEE
GROUP BY DEPT_CODE
ORDER BY 평균급여 DESC
;
SELECT ROWNUM, 평균급여
FROM(
SELECT DEPT_CODE, ROUND(AVG(SALARY)) 평균급여
FROM EMPLOYEE
GROUP BY DEPT_CODE
ORDER BY 평균급여 DESC
) E
WHERE ROWNUM <= 3;
SELECT ROWNUM, E.*
FROM
(SELECT EMP_NAME, SALARY, HIRE_DATE
FROM EMPLOYEE
ORDER BY HIRE_DATE DESC ) E
WHERE ROWNUM <= 5;
WITH EMP_HIRE AS (
SELECT EMP_NAME, SALARY, HIRE_DATE
FROM EMPLOYEE
ORDER BY HIRE_DATE DESC
)
SELECT EMP_NAME, SALARY, HIRE_DATE
FROM EMP_HIRE
WHERE ROWNUM <= 5;
SELECT EMP_NAME, SALARY, ROW_NUMBER() OVER(ORDER BY SALARY DESC) 순위
FROM EMPLOYEE;
WITH EMP_SAL_DESC AS(SELECT
EMP_NAME,
SALARY,
ROW_NUMBER() OVER(ORDER BY SALARY DESC) 순위
FROM EMPLOYEE
)
SELECT EMP_NAME, SALARY, 순위
FROM EMP_SAL_DESC
WHERE 순위 <=5;