서브쿼리
* 하나의 주된 SQL문(SELECT, INSERT, UPDATE, CREATE, ...)안에 포함된 SELECT문
* 메인 SQL문을 위해 보조역할을 하는 쿼리문임.
*
* [구분]
* - 단일행 단일열 서브쿼리 : 서브쿼리 부분을 수행한 결과값이 오로지 1칸일때
* - 다중행 단일열 서브쿼리 : 서브쿼리 부분을 수행한 결과값이 여러 행일 경우 (세로 한 줄)
* - 단일행 다중열 서브쿼리 : 서브쿼리 부분을 수행한 결과값이 여러 열일 경우 (가로 한 줄)
* - 다중행 다중열 서브쿼리 : 서브쿼리 부분을 수행한 결과값이 여러 행, 여러 열일 경우
* => 서브쿼리는 기본적으로 WHERE,HAVING절에 들어가기 때문에
* => 서브쿼리를 수행한 결과가 몇행, 몇열이냐에 따라서 사용가능한 연산자의 종류도 달라짐
*
* 추가. "인라인 뷰" : 서브쿼리이긴 서브쿼리인데, FROM절에 들어가는 서브쿼리
SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME ='노옹철';
SELECT EMP_NAME, DEPT_CODE
FROM EMPLOYEE
WHERE DEPT_CODE = 'D9';
SELECT EMP_NAME, DEPT_CODE
FROM EMPLOYEE
WHERE DEPT_CODE = (SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME ='노옹철');
SELECT AVG(SALARY)
FROM EMPLOYEE;
SELECT EMP_ID, EMP_NAME, JOB_CODE
FROM EMPLOYEE
WHERE SALARY >= 3047662;
SELECT EMP_ID, EMP_NAME, JOB_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY >= (SELECT AVG(SALARY)
FROM EMPLOYEE);
단일행 단일열 서브쿼리
* 서브쿼리의 조회결과가 오로지 1칸인 경우
* 일반연산자 사용 가능 : =, !=, <=, >, ...
SELECT ROUND(AVG(SALARY))
FROM EMPLOYEE;
SELECT EMP_NAME, JOB_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY <= 3047663;
SELECT EMP_NAME, JOB_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY <= (SELECT ROUND(AVG(SALARY))
FROM EMPLOYEE);
SELECT MIN(SALARY)
FROM EMPLOYEE;
SELECT EMP_ID, EMP_NAME, JOB_CODE, SALARY, HIRE_DATE
FROM EMPLOYEE
WHERE SALARY = 1380000;
SELECT EMP_ID, EMP_NAME, JOB_CODE, SALARY, HIRE_DATE
FROM EMPLOYEE
WHERE SALARY = (SELECT MIN(SALARY)
FROM EMPLOYEE);
SELECT SALARY
FROM EMPLOYEE
WHERE EMP_NAME = '노옹철';
SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY > 3700000;
SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY > (SELECT SALARY
FROM EMPLOYEE
WHERE EMP_NAME = '노옹철');
SELECT SALARY
FROM EMPLOYEE
WHERE EMP_NAME = '노옹철';
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, SALARY
FROM EMPLOYEE E, DEPARTMENT D
WHERE E.DEPT_CODE = D.DEPT_ID(+)
AND SALARY > 3700000;
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, SALARY
FROM EMPLOYEE E, DEPARTMENT D
WHERE E.DEPT_CODE = D.DEPT_ID(+)
AND SALARY > (SELECT SALARY
FROM EMPLOYEE
WHERE EMP_NAME = '노옹철');
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, SALARY
FROM EMPLOYEE E
LEFT JOIN DEPARTMENT D ON(E.DEPT_CODE = D.DEPT_ID)
WHERE SALARY > (SELECT SALARY
FROM EMPLOYEE
WHERE EMP_NAME = '노옹철');
SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME = '전지연';
SELECT EMP_ID, EMP_NAME, PHONE, JOB_NAME
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE
AND DEPT_CODE = 'D1'
AND EMP_NAME != '전지연';
SELECT EMP_ID, EMP_NAME, PHONE, JOB_NAME
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE
AND DEPT_CODE = (SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME = '전지연')
AND EMP_NAME != '전지연';
SELECT EMP_ID, EMP_NAME, PHONE, JOB_NAME
FROM EMPLOYEE
JOIN JOB USING(JOB_CODE)
WHERE DEPT_CODE = (SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME = '전지연')
AND EMP_NAME != '전지연';
SELECT DEPT_CODE, SUM(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE;
SELECT MAX(SUM(SALARY))
FROM EMPLOYEE
GROUP BY DEPT_CODE;
SELECT DEPT_CODE, DEPT_TITLE, SUM(SALARY)
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE = DEPT_ID(+)
GROUP BY DEPT_CODE, DEPT_TITLE
HAVING SUM(SALARY) = 17700000;
SELECT DEPT_CODE, DEPT_TITLE, SUM(SALARY)
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE = DEPT_ID(+)
GROUP BY DEPT_CODE, DEPT_TITLE
HAVING SUM(SALARY) = (SELECT MAX(SUM(SALARY))
FROM EMPLOYEE
GROUP BY DEPT_CODE);
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);
다중행 단일열 서브쿼리
* 서브쿼리에 조회결과값이 여러 행일때(세로 한 줄)
*
* IN : '일치'의 의미
* - IN(10,20,30,40) 서브쿼리 : 여러개의 결과값 중에서, 한개라도 일치하는 값이 있다면 조회
* NOT IN() : 일치하는 값이 없으면 조회
* ANY : '하나라도'의 의미
* - 컬럼명 > ANY(10,20,30) 서브쿼리 : 여러개의 결과값 중에서, '하나라도' 클 경우 조회
* 즉, 여러개의 결과값 중에서, 가장 작은 값(10)보다 클 경우 조회
* - 컬럼명 < ANY(10,20,30) 서브쿼리 : 여러개의 결과값 중에서, '하나라도' 작을 경우 조회
* 즉, 여러개의 결과값 중에서, 가장 큰 값(30) 보다 작을 경우 조회
* ALL : '모두'의 의미
* - 컬럼명 > ALL(10,20,30) 서브쿼리 : 여러개의 결과값의 '모든' 값보다 클 경우
* 즉, 여러개의 결과값 중에서, 가장 큰 값(30)보다 클 경우 조회
* - 컬럼명 < ALL(10,20,30) 서브쿼리 : 여러개의 결과값의 '모든' 값보다 작을 경우
* 즉, 여러개의 결과값 중에서, 가장 작은 값(10)보다 작을 경우 조회
SELECT MAX(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE;
SELECT EMP_NAME, JOB_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY IN(2890000, 3660000, 8000000, 3760000, 3900000, 2490000, 2550000);
SELECT EMP_NAME, JOB_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY IN(SELECT MAX(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE);
SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME IN ('선동일','유재식');
SELECT EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE IN('D9', 'D6');
SELECT EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE IN(SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME IN ('선동일','유재식'));
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 SALARY > ANY(2200000, 2500000, 3760000);
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE
AND SALARY > ANY(2200000, 2500000, 3760000)
AND JOB_NAME = '대리';
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE
AND SALARY > ANY(SELECT SALARY
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE
AND JOB_NAME = '과장')
AND J.JOB_NAME = '대리';
SELECT SALARY
FROM EMPLOYEE E
JOIN JOB J ON(E.JOB_CODE = J.JOB_CODE)
WHERE JOB_NAME ='차장';
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE E
JOIN JOB J ON(E.JOB_CODE = J.JOB_CODE)
WHERE JOB_NAME = '과장'
AND SALARY > ALL(2800000, 1550000, 2490000, 2480000);
SELECT EMP_ID, EMP_NAME, JOB_NAME, SALARY
FROM EMPLOYEE E
JOIN JOB J ON(E.JOB_CODE = J.JOB_CODE)
WHERE JOB_NAME = '과장'
AND SALARY > ALL(SELECT SALARY
FROM EMPLOYEE E
JOIN JOB J ON(E.JOB_CODE = J.JOB_CODE)
WHERE JOB_NAME ='차장');
단일행 다중열 서브쿼리
* 조회 결과값은 한 행이지만, 나열된 컬럼수가 여러 개일때 (가로 한 줄)
* (여러개) = (여러개)
* => 순서가 맞아 떨어져야 함.
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 = (SELECT DEPT_CODE
FROM EMPLOYEE
WHERE EMP_NAME = '하이유')
AND JOB_CODE = (SELECT JOB_CODE
FROM EMPLOYEE
WHERE EMP_NAME = '하이유')
AND 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 = '하이유')
AND EMP_NAME != '하이유';
SELECT *
FROM EMPLOYEE;
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 ='박나라')
AND EMP_NAME != '박나라';
다중행 다중열 서브쿼리
* 서브쿼리 조회 결과가 여러행, 여러열일 경우
* (비교할 컬럼명들) IN(서브쿼리) => 순서를 맞춰줘야 함.
SELECT JOB_CODE, MIN(SALARY)
FROM EMPLOYEE
GROUP BY JOB_CODE;
SELECT JOB_CODE, MIN(SALARY)
FROM EMPLOYEE
SELECT EMP_ID, EMP_NAME, JOB_CODE, SALARY
FROM EMPLOYEE
WHERE (JOB_CODE, SALARY) IN (('J2',3700000),
('J7',1380000),
('J3',3400000),
('J6',2000000),
('J5',2200000),
('J1',8000000),
('J4',1550000));
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 NVL(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,'없음'), SALARY) IN (('없음', 2890000),
('D1',3660000),
('D9',8000000),
('D5',3760000),
('D6',3900000),
('D2', 2490000),
('D8',2550000));
SELECT EMP_ID, EMP_NAME,NVL(DEPT_CODE,'없음'), SALARY
FROM EMPLOYEE
WHERE (NVL(DEPT_CODE,'없음'), SALARY) IN (SELECT NVL(DEPT_CODE,'없음'), MAX(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE)
ORDER BY SALARY DESC;
인라인 뷰
* FROM 절에 서브쿼리를 제시하는 것
* FROM 테이블명
* FROM (서브쿼리) => FROM ResultSet
* 서브쿼리를 수행한 결과 (ResultSet) 을 테이블 대신에 사용함
SELECT EMP_ID "사번", EMP_NAME "이름", (SALARY + (SALARY * NVL(BONUS, 0))) * 12 "보너스 포함 연봉", DEPT_CODE "부서코드"
FROM EMPLOYEE
WHERE (SALARY + (SALARY * NVL(BONUS, 0))) * 12 >= 30000000;
SELECT "사번", "이름", "보너스 포함 연봉", "부서코드"
FROM (SELECT EMP_ID "사번", EMP_NAME "이름", (SALARY + (SALARY * NVL(BONUS, 0))) * 12 "보너스 포함 연봉", DEPT_CODE "부서코드"
FROM EMPLOYEE)
WHERE "보너스 포함 연봉" >= 30000000;
SELECT ROWNUM, EMP_NAME, SALARY
FROM EMPLOYEE
WHERE ROWNUM <= 5
ORDER BY SALARY DESC;
SELECT ROWNUM "순위", EMP_NAME, SALARY
FROM (SELECT *
FROM EMPLOYEE
ORDER BY SALARY DESC)
WHERE ROWNUM <= 5;
SELECT ROWNUM, E.*
FROM (SELECT *
FROM EMPLOYEE
ORDER BY SALARY DESC) E
WHERE ROWNUM <= 5;
SELECT ROWNUM, DEPT_CODE, "평균 급여"
FROM (SELECT DEPT_CODE, AVG(SALARY) "평균 급여"
FROM EMPLOYEE
GROUP BY DEPT_CODE
ORDER BY AVG(SALARY) DESC)
WHERE ROWNUM <= 3;
SELECT ROWNUM "순번", E.*
FROM (SELECT EMP_NAME "이름", SALARY "급여", HIRE_DATE "입사일"
FROM EMPLOYEE
ORDER BY HIRE_DATE DESC) E
WHERE ROWNUM <= 5;
순위함수
* RANK() OVER(정렬기준)
* DENSE_RANK() OVER(정렬기준)
*
* 차이점
* RANK() OVER(정렬기준) : 공동 1위가 3명이라고 한다면 그 다음 순위를 4위로 하겠다.
* => 공동 N위가 M명이면 다음순위는 N+M위
* DENSE_RANK() OVER(정렬기준) : 공동 1위가 3명이여도 그 다음 순위는 무조건 2위로 하겠다.
* => 공동 N위가 M명이여도 다음순위는 N+1위
*
* 주의사항 : SELECT 절에만 작성가능
SELECT EMP_NAME, SALARY, ROWNUM "순위"
FROM (SELECT EMP_NAME, SALARY
FROM EMPLOYEE
ORDER BY SALARY DESC);
SELECT EMP_NAME, SALARY, RANK() OVER(ORDER BY SALARY DESC) "순위"
FROM EMPLOYEE;
SELECT EMP_NAME, SALARY, DENSE_RANK() OVER(ORDER BY SALARY DESC) "순위"
FROM EMPLOYEE;
SELECT EMP_NAME, SALARY, RANK() OVER(ORDER BY SALARY DESC) "순위"
FROM EMPLOYEE
WHERE RANK() OVER(ORDER BY SALARY DESC) <= 5;
SELECT *
FROM (SELECT EMP_NAME, SALARY, RANK() OVER(ORDER BY SALARY DESC) "순위"
FROM EMPLOYEE)
WHERE "순위" <= 5;
SELECT EMP_ID, EMP_NAME, *
FROM EMPLOYEE;
SELECT ROWNUM, E.*
FROM (SELECT EMP_NAME, SALARY, RANK() OVER(ORDER BY SALARY DESC) "순위"
FROM EMPLOYEE) E
WHERE "순위" <= 5;