--1. 박정보 사원의 부서코드 조회
SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME = '박정보';
--2. 부서코드가 D9인 사원들의 이름 조회
SELECT EMP_NAME
FROM EMPLOYEE
WHERE DEPT_CODE = 'D9';
--위의 단계를 하나의 쿼리문으로
SELECT EMP_NAME
FROM EMPLOYEE
WHERE DEPT_CODE = (SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME = '박정보');
SELECT EMP_ID, EMP_NAME, JOB_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY >= (SELECT AVG(SALARY)
FROM EMPLOYEE);
서브쿼리를 수행한 결과값이 몇행 몇열이냐에 따라 분류
서브쿼리의 종류가 무엇이냐에 따라 서브쿼리 앞에 붙는 연산자가 달라짐
서브쿼리 조회 결과값이 오로지 하나일 때
일반 비교연산자 사용가능
=, !=, >, =< 등
SELECT EMP_NAME, JOB_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY < (SELECT AVG(SALARY)
FROM EMPLOYEE)
ORDER BY SALARY;
SELECT EMP_ID, EMP_NAME, SALARY, HIRE_DATE
FROM EMPLOYEE
WHERE SALARY = (SELECT MIN(SALARY)
FROM EMPLOYEE);
SELECT EMP_ID, EMP_NAME, SALARY
FROM EMPLOYEE
WHERE SALARY > (SELECT SALARY
FROM EMPLOYEE
WHERE EMP_NAME = '박정보');
-->>오라클 전용 구문
SELECT EMP_ID, EMP_NAME, DEPT_CODE, DEPT_TITLE, SALARY
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE = DEPT_ID
AND SALARY > (SELECT SALARY
FROM EMPLOYEE
WHERE EMP_NAME = '박정보');
-->>ANSI 구문
SELECT EMP_ID, EMP_NAME, DEPT_CODE, DEPT_TITLE, SALARY
FROM EMPLOYEE
JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID)
WHERE SALARY > (SELECT SALARY
FROM EMPLOYEE
WHERE EMP_NAME = '박정보');
SELECT EMP_ID, EMP_NAME, PHONE, DEPT_TITLE
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE = DEPT_ID
AND DEPT_CODE = (SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME = '구정하')
AND EMP_NAME != '구정하';
SELECT EMP_ID, EMP_NAME, PHONE, DEPT_TITLE
FROM EMPLOYEE
JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID)
WHERE DEPT_CODE = (SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME = '구정하')
AND EMP_NAME != '구정하';
--6.1 부서별 급여합 중 가장 큰 값
SELECT MAX(SUM(SALARY))
FROM EMPLOYEE
GROUP BY DEPT_CODE;
--6.2 부서별 급여합이 17700000인 부서 조회
SELECT DEPT_CODE, SUM(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE
HAVING SUM(SALARY)= 17700000;
--위의 쿼리문을 하나로
SELECT DEPT_CODE, SUM(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE
HAVING SUM(SALARY)= (SELECT MAX(SUM(SALARY))
FROM EMPLOYEE
GROUP BY DEPT_CODE);
서브쿼리 조회 결과값이 여러행일 때(여러행 한열)
비교대상 > ANY(값1, 값2, 값3)
=비교대상 > 값1 OR 비교대상 > 값2 OR 비교대상 > 값3
(가장 작은 값보다 크면 됨)
SELECT SALARY
FROM EMPLOYEE
JOIN JOB USING (JOB_CODE)
WHERE JOB_NAME = '과장'; -- 2200000, 2500000, 3760000
--직급이 대리이면서 급여값이 위 값들 중에서 하나라도 큰 사원의 위 조건 조회
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE
JOIN JOB USING(JOB_CODE)
WHERE JOB_NAME = '대리'
AND SALARY > ANY (2200000, 2500000, 3760000);
-- 위의 쿼리문을 하나로
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE
JOIN JOB USING(JOB_CODE)
WHERE JOB_NAME = '대리'
AND SALARY > ANY (SELECT SALARY
FROM EMPLOYEE
JOIN JOB USING (JOB_CODE)
WHERE JOB_NAME = '과장');
-- MIN을 넣어 단일행 서브쿼리로도 가능
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE
JOIN JOB USING(JOB_CODE)
WHERE JOB_NAME = '대리'
AND SALARY > (SELECT MIN(SALARY)
FROM EMPLOYEE
JOIN JOB USING (JOB_CODE)
WHERE JOB_NAME = '과장');
--ANY: 차장의 최소급여보다 많이 받는 과장
-- 비교대상 > 값1 OR 비교대상 > 값2 OR 비교대상 > 값3
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE
JOIN JOB USING(JOB_CODE)
WHERE JOB_NAME = '과장'
AND SALARY > ANY (SELECT SALARY
FROM EMPLOYEE
JOIN JOB USING (JOB_CODE)
WHERE JOB_NAME = '차장');
--ALL: 차장의 최대급여보다 많이 받는 과장
--비교대상 > 값1 AND 비교대상 > 값2 AND 비교대상 > 값3
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE
JOIN JOB USING(JOB_CODE)
WHERE JOB_NAME = '과장'
AND SALARY > ALL (SELECT SALARY
FROM EMPLOYEE
JOIN JOB USING (JOB_CODE)
WHERE JOB_NAME = '차장');
결과값은 한행이지만 나열된 컬럼 수가 여러개일 경우
SELECT EMP_NAME, DEPT_CODE, JOB_CODE, HIRE_DATE
FROM EMPLOYEE
WHERE DEPT_CODE = (SELECT DEPT_CODE --장정보의 부서코드 구하기
FROM EMPLOYEE
WHERE EMP_NAME = '장정보')
AND JOB_CODE = (SELECT JOB_CODE --장정보의 직급코드 구하기
FROM EMPLOYEE
WHERE EMP_NAME = '장정보');
--위의 쿼리문을 다중열 서브쿼리로
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_ID, EMP_NAME, JOB_CODE, MANAGER_ID
FROM EMPLOYEE
WHERE (JOB_CODE, MANAGER_ID) = (SELECT JOB_CODE, MANAGER_ID
FROM EMPLOYEE
WHERE EMP_NAME = '지정보');
서브쿼리 조회 결과값이 여러행 여러열일 경우
SELECT EMP_ID, EMP_NAME, JOB_CODE, SALARY
FROM EMPLOYEE
WHERE (JOB_CODE, SALARY) IN (SELECT JOB_CODE, MIN(SALARY)
FROM EMPLOYEE
GROUP BY JOB_CODE);
SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE (DEPT_CODE, SALARY) IN (SELECT DEPT_CODE, MAX(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE);
(VIEW:사용자한테 보여주는 가상테이블)
FROM절에 서브쿼리 작성
서브쿼리를 수행한 결과를 마치 테이블처럼 사용
연봉이 NULL이 없도록 함
조건: 연봉이 3000만원 이상인 사원들만 조회
-WHERE절에 별칭 사용하고 싶으면 INLINE VIEW사용
SELECT *
FROM (SELECT EMP_ID, EMP_NAME, (SALARY*NVL(1+BONUS,1))*12 연봉, DEPT_CODE
FROM EMPLOYEE) --TABLE처럼 사용
WHERE 연봉 >= 30000000;
SELECT 이름, 연봉 --FROM의 테이블에 있는 컬럼만 가져올 수 있음(PHONE은 가져올 수X)
FROM (SELECT EMP_ID, EMP_NAME 이름, (SALARY*NVL(1+BONUS,1))*12 연봉, DEPT_CODE
FROM EMPLOYEE) --TABLE처럼 사용
WHERE 연봉 >= 30000000;
-INLINE VIEW를 주로 사용하는 예 => TOP-N분석(상위 몇위만 가져오기)
★ROWNUM : 오라클에서 제공해주는 컬럼, 조회된 순서대로 1부터 순번을 부여해주는 컬럼
SELECT ROWNUM, EMP_NAME, SALARY
FROM EMPLOYEE;
SELECT ROWNUM, EMP_NAME, SALARY --ROWNUM으로 넘버링 된 값은 정렬 할당해도 바뀌지 않음
FROM EMPLOYEE
ORDER BY SALARY DESC; --정렬은 맨 마지막에 실행하기 때문에. 그래서 INLINE VIEW 사용
--ORDER BY절이 다 실행된 결과로 ROWNUM을 부여한 후 5명 추출
SELECT ROWNUM, EMP_NAME, SALARY
FROM (SELECT EMP_NAME, SALARY
FROM EMPLOYEE
ORDER BY SALARY DESC)
WHERE ROWNUM <=5;
--테이블 별칭 부여하여 간결하게
SELECT ROWNUM, E.*
FROM (SELECT EMP_NAME, SALARY
FROM EMPLOYEE
ORDER BY SALARY DESC) E
WHERE ROWNUM <=5;
SELECT ROWNUM, E.*
FROM (SELECT EMP_NAME, SALARY, HIRE_DATE
FROM EMPLOYEE
ORDER BY HIRE_DATE DESC) E
WHERE ROWNUM <= 5;
푸는 법 두 가지
SELECT *
FROM (SELECT DEPT_CODE, CEIL(AVG(SALARY)) 평균급여
FROM EMPLOYEE
GROUP BY DEPT_CODE
ORDER BY 2 DESC) E
WHERE ROWNUM <= 3;
서브쿼리에 이름을 붙여주고 인라인 뷰로 사용시 서브쿼리의 이름으로 FROM 절에 기술
-장점
같은 서브쿼리가 여러번 사용될 경우 중복 작성을 피할 수 있고
실행속도도 빨라진다
WITH 서브쿼리명 AS (서브쿼리)
WITH SAL3 AS (SELECT DEPT_CODE, CEIL(AVG(SALARY)) 평균급여
FROM EMPLOYEE
GROUP BY DEPT_CODE
ORDER BY 2 DESC)
SELECT DEPT_CODE, 평균급여
FROM SAL3
WHERE ROWNUM <= 3;
RANK() OVER(정렬기준) | DENSE_RANK() OVER(정렬기준)
두 함수는 무조건 SELECT절에서만 사용!
-RANK() OVER(정렬기준): 동일한 순위 이후의 등수를 동일한 인원 수 만큼 건너뛰고 순위 계산
EX) 공동 12위가 2명이면 그 다음은 14위
-DENSE_RANK() OVER(정렬기준): 동일한 순위 이후의 등수는 인원수와 상관없이 1을 증가시킨 순위
EX) 공동 12위가 2명이면 그 다음은 13위
SELECT EMP_NAME, SALARY, RANK() OVER(ORDER BY SALARY DESC) 순위
FROM EMPLOYEE;
20위 건너뛴 결과가 나옴
SELECT EMP_NAME, SALARY, DENSE_RANK() OVER(ORDER BY SALARY DESC) 순위
FROM EMPLOYEE;
총 인원은 23명인데 22위까지 밖에 없음
SELECT *
FROM (SELECT EMP_NAME, SALARY, RANK() OVER(ORDER BY SALARY DESC) 순위
FROM EMPLOYEE)
WHERE 순위 <= 5; --WHERE절에 RANK조건을 줄 수 없어서 INLINE VIEW를 통해 조회
WITH TOP_SALARY AS (SELECT EMP_NAME, SALARY, RANK() OVER(ORDER BY SALARY DESC) 순위
FROM EMPLOYEE)
SELECT 순위, EMP_NAME, SALARY
FROM TOP_SALARY
WHERE 순위 <= 5;