ORACLE
OracleStudy / 20220224_01_scott.sql / cube() rollup()
universedevelope
2022. 7. 3. 09:52
SELECT USER
FROM DUAL;
--==>> SCOTT
SELECT DEPTNO, SAL
FROM EMP
ORDER BY 1;
/*
10 2450┐
10 5000│ 8750
10 1300┘
20 29750┐
20 3000 │
20 1100 │ 10875
20 800 │
20 3000 ┘
30 12500┐
30 1500 │
30 1600 │
30 950 │ 9400
30 2850 │
30 1250 ┘
*/
SELECT DEPTNO, SUM(SAL)
FROM EMP
GROUP BY DEPTNO
ORDER BY 1;
/*
10 8750
20 10875
30 9400
*/
-- ○ 기존에 복사해둔 TBL_EMP 테이블 제거
DROP TABLE TBL_EMP;
--==>> Table TBL_EMP이(가) 삭제되었습니다.
-- ○ 다시 EMP 테이블 복사하여 TBL_EMP 테이블 생성
CREATE TABLE TBL_EMP
AS
SELECT *
FROM EMP;
--==>> Table TBL_EMP이(가) 생성되었습니다.
-- ○ 실습 데이터 추가 입력(TBL_EMP)
INSERT INTO TBL_EMP VALUES
(8001, '홍은혜', 'CLERK', 7566, SYSDATE, 1500, 10, NULL);
--==>> 1 행 이(가) 삽입되었습니다.
INSERT INTO TBL_EMP VALUES
(8002, '김상기', 'CLERK', 7566, SYSDATE, 2000, 10, NULL);
--==>> 1 행 이(가) 삽입되었습니다.
INSERT INTO TBL_EMP VALUES
(8003, '이호석', 'SALESMAN', 7698, SYSDATE, 1700, NULL, NULL);
--==>> 1 행 이(가) 삽입되었습니다.
INSERT INTO TBL_EMP VALUES
(8004, '신시은', 'SALESMAN', 7698, SYSDATE, 2500, NULL, NULL);
--==>> 1 행 이(가) 삽입되었습니다.
INSERT INTO TBL_EMP VALUES
(8005, '김태형', 'SALESMAN', 7698, SYSDATE, 1000, NULL, NULL);
--==>> 1 행 이(가) 삽입되었습니다.
SELECT *
FROM TBL_EMP;
/*
7369 SMITH CLERK 7902 1980-12-17 800 (null) 20
7499 ALLEN SALESMAN 7698 1981-02-20 1600 300 30
7521 WARD SALESMAN 7698 1981-02-22 1250 500 30
7566 JONES MANAGER 7839 1981-04-02 2975 (null) 20
7654 MARTIN SALESMAN 7698 1981-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 1981-05-01 2850 (null) 30
7782 CLARK MANAGER 7839 1981-06-09 2450 (null) 10
7788 SCOTT ANALYST 7566 1987-07-13 3000 (null) 20
7839 KING PRESIDENT (null) 1981-11-17 5000 (null) 10
7844 TURNER SALESMAN 7698 1981-09-08 1500 0 30
7876 ADAMS CLERK 7788 1987-07-13 1100 (null) 20
7900 JAMES CLERK 7698 1981-12-03 950 (null) 30
7902 FORD ANALYST 7566 1981-12-03 3000 (null) 20
7934 MILLER CLERK 7782 1982-01-23 1300 (null) 10
8001 홍은혜 CLERK 7566 2022-02-24 1500 10 (null)
8002 김상기 CLERK 7566 2022-02-24 2000 10 (null)
8003 이호석 SALESMAN 7698 2022-02-24 1700 (null) (null)
8004 신시은 SALESMAN 7698 2022-02-24 2500 (null) (null)
8005 김태형 SALESMAN 7698 2022-02-24 1000 (null) (null)
*/
-- ○ 커밋
COMMIT;
--==>> 커밋 완료.
SELECT DEPTNO, SAL, COMM
FROM TBL_EMP
ORDER BY COMM DESC;
/*
20 800 (null)
1700 (null)
1000 (null)
10 1300 (null)
20 2975 (null)
30 2850 (null)
10 2450 (null)
20 3000 (null)
10 5000 (null)
2500 (null)
20 1100 (null)
30 950 (null)
20 3000 (null)
30 1250 1400
30 1250 500
30 1600 300
1500 10
2000 10
30 1500 0
*/
-- ※ 오라클에서는 NULL 을 가장 큰 값의 형태로 간주한다.
-- (ORACLE 9i 이전까지는 NULL 을 가장 작은 값의 형태로 간주했었다.)
-- MSSQL 은 NULL 을 가장 작은 값의 형태로 간주한다.
-- ○ TMP_EMP 테이블을 대상으로 부서별 급여합 조회
-- 부서번호, 급여합 항목 조회
SELECT DEPTNO, SUM(SAL)
FROM TBL_EMP
GROUP BY DEPTNO
ORDER BY DEPTNO;
/*
10 8750
20 10875
30 9400
(null) 8700
*/
-- ○ ROLLUP 사용
SELECT DEPTNO, SUM(SAL)
FROM TBL_EMP
GROUP BY ROLLUP(DEPTNO);
/*
10 8750
20 10875
30 9400
(null) 8700 -- 부서번호를 갖지 못한 직원들의 급여 합
(null) 37725 -- 모든부서 직원들의 급여합
*/
SELECT DEPTNO "부서번호", SUM(SAL) "급여합"
FROM EMP
GROUP BY ROLLUP(DEPTNO);
/*
10 8750
20 10875
30 9400
(null) 29025
*/
/*
------- -------
부서번호 급여합
------- -------
10 8750
20 10875
30 9400
모든부서 29025
*/
SELECT NVL(TO_CHAR(DEPTNO), '모든부서') "부서번호", SUM(SAL) "급여합"
FROM EMP
GROUP BY ROLLUP(DEPTNO);
/*
10 8750
20 10875
30 9400
모든부서 29025
*/
SELECT GROUPING(DEPTNO) "GROUPING", DEPTNO "부서번호", SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY ROLLUP(DEPTNO);
/*
GROUPING 부서번호 급여합
-------- --------- -------
0 10 8750
0 20 10875
0 30 9400
0 (null) 8700 -- 인턴
1 (null) 37725 -- 모든부서
*/
SELECT DEPTNO "부서번호", SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY ROLLUP(DEPTNO);
-- ○ 위에서 조회한 해당 내용을
/*
10 8750
20 10875
30 9400
인턴 8700
모든부서 37725
*/
-- 이와같이 조회될 수 있도록 쿼리문을 구성한다.
SELECT CASE GROUPING(DEPTNO)
WHEN 0 THEN NVL(TO_CHAR(DEPTNO), '인턴')
ELSE '모든부서'
END "부서번호"
, SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY ROLLUP(DEPTNO);
/*
10 8750
20 10875
30 9400
인턴 8700
모든부서 37725
*/
-- ○ TBL_SAWON 테이블을 대상으로
-- 다음과 같이 조회될 수 있도록 쿼리문을 구성한다.
/*
-------------------------------
성별 급여합
-------------------------------
남 XXXXX
여 XXXXX
모든사원 XXXXX
-------------------------------
*/
SELECT CASE GROUPING(T.성별) WHEN 0 THEN T.성별
ELSE '모든사원'
END "성별1"
, NVL(TO_CHAR(T.성별), '모든사원') "성별2"
, SUM(T.급여) "급여합"
FROM
(
SELECT CASE WHEN SUBSTR(JUBUN, 7, 1) IN ('1', '3') THEN '남'
WHEN SUBSTR(JUBUN, 7, 1) IN ('2', '4') THEN '여'
ELSE '성별확인 불가'
END "성별"
, SAL "급여"
FROM TBL_SAWON
)T
GROUP BY ROLLUP(T.성별);
/*
------- ----------
성별 급여합
------- ----------
남 21900
여 33100
모든사원 55000
*/
SELECT *
FROM VIEW_SAWON;
-- ○ TBL_SAWON 테이블을 대상으로
-- 다음과 같이 조회될 수 있도록 연령대별 인원수를
-- 확인할 수 있는 쿼리문을 구성한다.
/*
--------------------
연령대 인원수
--------------------
10 X
20 X
40 X
50 X
전체 XX
--------------------
*/
-- 나의 방법 ①
SELECT CASE GROUPING(Y.연령대) WHEN 0 THEN TO_CHAR(Y.연령대)
ELSE '전체'
END "연령대"
, COUNT(Y.연령대) "인원수"
FROM
(
SELECT CASE WHEN T.나이 >= 50 THEN 50
WHEN T.나이 >= 40 THEN 40
WHEN T.나이 >= 20 THEN 20
WHEN T.나이 >= 10 THEN 10
ELSE 10000
END "연령대"
FROM
(
SELECT CASE WHEN SUBSTR(JUBUN, 7, 1) IN ('1', '2')
THEN EXTRACT(YEAR FROM SYSDATE) - (TO_NUMBER(SUBSTR(JUBUN, 1, 2))+1899)
WHEN SUBSTR(JUBUN, 7, 1) IN ('3', '4')
THEN EXTRACT(YEAR FROM SYSDATE) - (TO_NUMBER(SUBSTR(JUBUN, 1, 2))+1999)
ELSE 0
END "나이"
FROM TBL_SAWON
)T
)Y
GROUP BY ROLLUP(Y.연령대)
ORDER BY Y.연령대;
/*
--------------------
연령대 인원수
--------------------
10 2
20 12
40 1
50 3
전체 18
*/
-- 나의 방법 ② (VIEW 두번생성)
CREATE OR REPLACE VIEW MYVIEW_TBL_SAWON
AS
SELECT CASE WHEN SUBSTR(JUBUN, 7, 1) IN ('1', '2')
THEN EXTRACT(YEAR FROM SYSDATE) - (TO_NUMBER(SUBSTR(JUBUN, 1, 2))+1899)
WHEN SUBSTR(JUBUN, 7, 1) IN ('3', '4')
THEN EXTRACT(YEAR FROM SYSDATE) - (TO_NUMBER(SUBSTR(JUBUN, 1, 2))+1999)
ELSE 0
END "나이"
FROM TBL_SAWON;
-- 1번째 VIEW 를 통한 2번째 VIEW 생성
CREATE OR REPLACE VIEW MYVIEW_TBL_SAWON2
AS
SELECT CASE WHEN K.나이 >= 50 THEN 50
WHEN K.나이 >= 40 THEN 40
WHEN K.나이 >= 20 THEN 20
WHEN K.나이 >= 10 THEN 10
ELSE -1
END "연령대"
FROM
(
SELECT *
FROM MYVIEW_TBL_SAWON
)K;
-- 2번째 VIEW를 통한 결과 조회
SELECT NVL(TO_CHAR(G.연령대), '전체') "연령대"
, COUNT(G.연령대) "인원수"
FROM
(
SELECT *
FROM MYVIEW_TBL_SAWON2
)G
GROUP BY ROLLUP(G.연령대);
/*
10 2
20 12
40 1
50 3
전체 18
*/
-- 선생님 방법 1. → INLINE VIEW 를 두 번 중첩(나의 1번과동일)
SELECT NVL(TO_CHAR(T2.연령대), '전체') "연령대"
, COUNT(*) "인원수"
FROM
(
-- 연령대
SELECT CASE WHEN T1.나이 >= 50 THEN 50
WHEN T1.나이 >= 40 THEN 40
WHEN T1.나이 >= 30 THEN 30
WHEN T1.나이 >= 20 THEN 20
WHEN T1.나이 >= 10 THEN 10
ELSE -123456789
END "연령대"
FROM
(
-- 나이
SELECT CASE WHEN SUBSTR(JUBUN, 7, 1) IN ('1', '2')
THEN EXTRACT(YEAR FROM SYSDATE)-(TO_NUMBER(SUBSTR(JUBUN, 1, 2))+1899)
WHEN SUBSTR(JUBUN, 7, 1) IN ('3', '4')
THEN EXTRACT(YEAR FROM SYSDATE)-(TO_NUMBER(SUBSTR(JUBUN, 1, 2))+1999)
ELSE -123123123
END "나이"
FROM TBL_SAWON
)T1
)T2
GROUP BY ROLLUP(T2.연령대);
/*
10 2
20 12
40 1
50 3
전체 18
*/
SELECT CASE GROUPING(T2.연령대) WHEN 0 THEN TO_CHAR(T2.연령대)
ELSE '전체'
END "연령대"
, COUNT(*) "인원수"
FROM
(
-- 연령대
SELECT CASE WHEN T1.나이 >= 50 THEN 50
WHEN T1.나이 >= 40 THEN 40
WHEN T1.나이 >= 30 THEN 30
WHEN T1.나이 >= 20 THEN 20
WHEN T1.나이 >= 10 THEN 10
ELSE -123456789
END "연령대"
FROM
(
-- 나이
SELECT CASE WHEN SUBSTR(JUBUN, 7, 1) IN ('1', '2')
THEN EXTRACT(YEAR FROM SYSDATE)-(TO_NUMBER(SUBSTR(JUBUN, 1, 2))+1899)
WHEN SUBSTR(JUBUN, 7, 1) IN ('3', '4')
THEN EXTRACT(YEAR FROM SYSDATE)-(TO_NUMBER(SUBSTR(JUBUN, 1, 2))+1999)
ELSE -123123123
END "나이"
FROM TBL_SAWON
)T1
)T2
GROUP BY ROLLUP(T2.연령대);
/*
10 2
20 12
40 1
50 3
전체 18
*/
-- 선생님 방법 2. → INLINE VIEW 를 한 번만 사용
-- 핵심 : 나이와 연령대의 계산에서, 범위를 정하는 것이아닌, 10의자리만
-- 확인해서 절삭하는 것.
SELECT TRUNC(21, -1) "RESULT"
FROM DUAL;
--==>> 20
SELECT CASE GROUPING(T.연령대 )WHEN 0 THEN TO_CHAR(T.연령대)
ELSE '전체'
END "연령대"
, COUNT(*) "인원수"
FROM
(
-- 연령대
SELECT TRUNC(CASE WHEN SUBSTR(JUBUN, 7, 1) IN ('1', '2')
THEN EXTRACT(YEAR FROM SYSDATE)-(TO_NUMBER(SUBSTR(JUBUN, 1, 2))+1899)
WHEN SUBSTR(JUBUN, 7, 1) IN ('3', '4')
THEN EXTRACT(YEAR FROM SYSDATE)-(TO_NUMBER(SUBSTR(JUBUN, 1, 2))+1999)
ELSE -123123123
END, -1) "연령대"
FROM TBL_SAWON
)T
GROUP BY ROLLUP(T.연령대);
/*
10 2
20 12
40 1
50 3
전체 18
*/
SELECT DEPTNO, JOB, SUM(SAL)
FROM EMP
GROUP BY DEPTNO, JOB
ORDER BY 1, 2;
/*
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
20 ANALYST 6000
20 CLERK 1900
20 MANAGER 2975
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
*/
SELECT DEPTNO, JOB, SUM(SAL)
FROM EMP
GROUP BY ROLLUP(DEPTNO, JOB)
ORDER BY 1, 2;
/*
10 CLERK 1300 -- 10부서 CLERK 직종의 급여합
10 MANAGER 2450 -- 10부서 MANAGER 직종의 급여합
10 PRESIDENT 5000 -- 10부서 PRESIDENT 직종의 급여합
10 (null) 8750 -- 10부서 모든 직종의 급여합
20 ANALYST 6000 -- 20부서 ANALYST 직종의 급여합
20 CLERK 1900 -- 20부서 CLERK 직종의 급여합
20 MANAGER 2975 -- 20부서 MANAGER 직종의 급여합
20 (null) 10875 -- 20부서 모든 직종의 급여합
30 CLERK 950 -- 30부서 CLERK 직종의 급여합
30 MANAGER 2850 -- 30부서 MANAGER 직종의 급여합
30 SALESMAN 5600 -- 30부서 SALESMAN 직종의 급여합
30 (null) 9400 -- 30부서 모든 직종의 급여합
(null) (null) 29025 -- 모든부서 모든 직종의 급여합
*/
-- ○ CUBE() → ROLLUP()보다 더 자세한 결과를 반환받는다.
SELECT DEPTNO, JOB, SUM(SAL)
FROM EMP
GROUP BY CUBE(DEPTNO, JOB)
ORDER BY 1, 2;
/*
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
10 (null) 8750
20 ANALYST 6000
20 CLERK 1900
20 MANAGER 2975
20 (null) 10875
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
30 (null) 9400
(null) ANALYST 6000 -- 모든 부서 ANALYST 직종의 급여합
(null) CLERK 4150 -- 모든 부서 CLERK 직종의 급여합
(null) MANAGER 8275 -- 모든 부서 MANAGER 직종의 급여합
(null) PRESIDENT 5000 -- 모든 부서 PRESIDENT 직종의 급여합
(null) SALESMAN 5600 -- 모든 부서 SALESMAN 직종의 급여합
(null) (null) 29025
*/
-- ※ ROLLUP() 과 CUBE()는
-- 그룹을 묶어주는 방식이 다르다.(차이)
-- EX)
-- ROLLUP(A, B, C)
-- →(A, B, C)/(A, B) /(A) / ()
-- CUBE(A, B, C)
-- →(A, B, C)/(A, B)/(A, C) / (B, C) / (A) / (B) / (C)/ ()
--==>> 위에서 사용한 것 ROLLUP() 은 묶음 방식이 다소 모자라고
-- 아래에서 사용한 것 CUBE() 는 묶음 방식이 다소 지나치기 때문에
-- 다음과 같은 방식의 쿼리 형태를 더 많이 사용한다.
-- 다음 작성하는 쿼리는 조회하고자 하는 그룹만 『GROUPING SETS』
-- 를 이용하여 묶어주는 방식이다.
SELECT CASE GROUPING(DEPTNO) WHEN 0 THEN NVL(TO_CHAR(DEPTNO), '인턴')
ELSE '전체부서'
END "부서번호"
, CASE GROUPING(JOB)WHEN 0 THEN JOB ELSE '전체직종'END "직종"
, SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY ROLLUP(DEPTNO, JOB)
ORDER BY 1, 2;
/*
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
10 전체직종 8750
20 ANALYST 6000
20 CLERK 1900
20 MANAGER 2975
20 전체직종 10875
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
30 전체직종 9400
인턴 CLERK 3500
인턴 SALESMAN 5200
인턴 전체직종 8700
전체부서 전체직종 37725
*/
SELECT CASE GROUPING(DEPTNO) WHEN 0 THEN NVL(TO_CHAR(DEPTNO), '인턴')
ELSE '전체부서'
END "부서번호"
, CASE GROUPING(JOB)WHEN 0 THEN JOB ELSE '전체직종'END "직종"
, SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY CUBE(DEPTNO, JOB)
ORDER BY 1, 2;
/*
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
10 전체직종 8750
20 ANALYST 6000
20 CLERK 1900
20 MANAGER 2975
20 전체직종 10875
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
30 전체직종 9400
인턴 CLERK 3500
인턴 SALESMAN 5200
인턴 전체직종 8700
전체부서 ANALYST 6000
전체부서 CLERK 7650
전체부서 MANAGER 8275
전체부서 PRESIDENT 5000
전체부서 SALESMAN 10800
전체부서 전체직종 37725
*/
SELECT CASE GROUPING(DEPTNO) WHEN 0 THEN NVL(TO_CHAR(DEPTNO), '인턴')
ELSE '전체부서'
END "부서번호"
, CASE GROUPING(JOB)WHEN 0 THEN JOB ELSE '전체직종'END "직종"
, SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY GROUPING SETS((DEPTNO, JOB), (DEPTNO), (JOB), ())
ORDER BY 1, 2;
/*
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
10 전체직종 8750
20 ANALYST 6000
20 CLERK 1900
20 MANAGER 2975
20 전체직종 10875
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
30 전체직종 9400
인턴 CLERK 3500
인턴 SALESMAN 5200
인턴 전체직종 8700
전체부서 ANALYST 6000
전체부서 CLERK 7650
전체부서 MANAGER 8275
전체부서 PRESIDENT 5000
전체부서 SALESMAN 10800
전체부서 전체직종 37725
*/
SELECT CASE GROUPING(DEPTNO) WHEN 0 THEN NVL(TO_CHAR(DEPTNO), '인턴')
ELSE '전체부서'
END "부서번호"
, CASE GROUPING(JOB)WHEN 0 THEN JOB ELSE '전체직종'END "직종"
, SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY GROUPING SETS((DEPTNO, JOB), (DEPTNO), ())
ORDER BY 1, 2;
/*
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
10 전체직종 8750
20 ANALYST 6000
20 CLERK 1900
20 MANAGER 2975
20 전체직종 10875
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
30 전체직종 9400
인턴 CLERK 3500
인턴 SALESMAN 5200
인턴 전체직종 8700
전체부서 전체직종 37725
*/
SELECT *
FROM TBL_EMP
ORDER BY HIREDATE;
-- ○ TBL_EMP 테이블을 대상으로
-- 입사년도별 인원수 인원수 총합 를 조회한다.
SELECT NVL(T.입사년도, '전체') "입사년도"
, COUNT(T.입사년도) "인원수"
FROM
(
SELECT TO_CHAR(HIREDATE, 'YYYY') "입사년도"
FROM TBL_EMP
)T
GROUP BY ROLLUP(T.입사년도)
ORDER BY 1, 2;
SELECT EXTRACT(YEAR FROM HIREDATE) "입사년도"
, COUNT(*)"인원수"
FROM TBL_EMP
GROUP BY ROLLUP(EXTRACT(YEAR FROM HIREDATE))
ORDER BY 1;
/*
1980 1
1981 10
1982 1
1987 2
2022 5
(null) 19
*/
SELECT EXTRACT(YEAR FROM HIREDATE) "입사년도"
, COUNT(*)"인원수"
FROM TBL_EMP
GROUP BY ROLLUP(TO_CHAR(HIREDATE, 'YYYY'))
ORDER BY 1;
--==>> 에러 발생
-- ORA-00979: not a GROUP BY expression
SELECT TO_CHAR(HIREDATE, 'YYYY') "입사년도"
, COUNT(*)"인원수"
FROM TBL_EMP
GROUP BY ROLLUP(TO_CHAR(HIREDATE, 'YYYY'))
ORDER BY 1;
/*
1980 1
1981 10
1982 1
1987 2
2022 5
(null) 19
*/
SELECT TO_CHAR(HIREDATE, 'YYYY') "입사년도"
, COUNT(*)"인원수"
FROM TBL_EMP
GROUP BY ROLLUP(EXTRACT(YEAR FROM HIREDATE))
ORDER BY 1;
--==>> 에러 발생
-- ORA-00979: not a GROUP BY expression
SELECT CASE GROUPING (TO_CHAR(HIREDATE, 'YYYY'))WHEN 0
THEN TO_CHAR(HIREDATE, 'YYYY')
ELSE '전체'
END "입사년도"
, COUNT(*)
FROM TBL_EMP
GROUP BY CUBE(TO_CHAR(HIREDATE, 'YYYY'))
ORDER BY 1;
/*
1980 1
1981 10
1982 1
1987 2
2022 5
전체 19
*/
SELECT CASE GROUPING (EXTRACT(YEAR FROM HIREDATE))WHEN 0
THEN TO_CHAR(EXTRACT(YEAR FROM HIREDATE))
ELSE '전체'
END "입사년도"
, COUNT(*)
FROM TBL_EMP
GROUP BY CUBE(EXTRACT(YEAR FROM HIREDATE))
ORDER BY 1;
/*
-1 19
1980 1
1981 10
1982 1
1987 2
2022 5
*/
--------------------------------------------------------------------------------
-- ■■■ HAVING ■■■ --
-- ○ EMP 테이블에서 부서번호가 20, 30 인 부서를 대상으로
-- 부서의 총 급여가 10000 보다 적을 경우만 부서별 총 급여를 조회한다.
SELECT NVL(TO_CHAR(DEPTNO), '모든부서') "부서번호", SUM(SAL) "급여"
FROM TBL_EMP
WHERE DEPTNO IN(20, 30)
GROUP BY ROLLUP(DEPTNO)
HAVING SUM(SAL) < 10000
ORDER BY 1;
--==>> 30 9400
--------------------------------------------------------------------------------
-- ■■■ 중첩 그룹함수 / 분석함수 ■■■ --
-- 그룹함수는 2 LEVEL 까지만 중첩해서 사용할 수 있다. = 중첩은 한번만된다.
-- MSSQL은 이마저도 불가능하다.
SELECT SUM(SAL)
FROM EMP
GROUP BY DEPTNO;
--==>>
/*
9400
10875
8750
*/
SELECT MAX(SUM(SAL))
FROM EMP
GROUP BY DEPTNO;
--==>>10875
SELECT MIN(SUM(SAL))
FROM EMP
GROUP BY DEPTNO;
--==>> 8750
-- ○ RANK()
-- DENSE_RANK()
--> ORACLE 9i 부터 적용.. MSSQL 2005부터 적용...
-- 하위 버전에서는 RANK()나 DENSE_RANK()를 사용할 수 없기 때문에
-- 예를 들어... 급여 순위를 구하고자 한다면..
-- 해당 사원의 급여보다 더 큰 값이 몇 개 인지 확인한 후
-- 확인한 값에 +1 을 추가연산해 주면...
-- 그 값이 곧 해당 사원의 급여 등수가 된다.
SELECT ENAME, SAL
FROM EMP;
/*
SMITH 800
ALLEN 1600
WARD 1250
JONES 2975
MARTIN 1250
BLAKE 2850
CLARK 2450
SCOTT 3000
KING 5000
TURNER 1500
ADAMS 1100
JAMES 950
FORD 3000
MILLER 1300
*/
-- ○ SMITH 의 급여 등수 확인
SELECT COUNT (*) + 1 -- : 등수
FROM EMP
WHERE SAL > 800; -- SMITH 의 급여
--==>> SMITH 의 급여등수 : 14
-- ○ ALLEN 의 급여등수 확인
SELECT COUNT(*) +1
FROM EMP
WHERE SAL >1600;
--==>> ALLEN 의 급여등수 : 7
-- ※ 서브 상관 쿼리(상관 서브 쿼리)
-- 메인 쿼리가 있는 테이블의 컬럼이
-- 서브 쿼리의 조건절(WHERE, HAVING)에 사용되는 경우
-- 우리는 이 쿼리문을 서브 상관 쿼리(상관 서브 쿼리)라고 부른다.
SELECT ENAME "사원명", SAL "급여"
, (SELECT COUNT (*) + 1
FROM EMP
WHERE SAL > E.SAL) "급여등수"
FROM EMP E;
/*
WARD 1250 10
JONES 2975 4
MARTIN 1250 10
BLAKE 2850 5
CLARK 2450 6
SCOTT 3000 2
KING 5000 1
TURNER 1500 8
ADAMS 1100 12
JAMES 950 13
FORD 3000 2
MILLER 1300 9
*/
-- ○ EMP 테이블을 대상으로
-- 사원명, 급여, 부서번호, 부서내 급여등수, 전체급여등수 항목을 조회
-- 단, RANK()함수를 사용하지 않고 서브상관쿼리를 활용할 수 있도록한다.
SELECT DEPTNO "부서번호", SAL "급여"
, (SELECT COUNT (*)+ 1
FROM EMP
WHERE SAL > K.SAL AND DEPTNO = 20)"급여순위"
FROM EMP K
WHERE DEPTNO = 20;
SELECT ENAME "사원명", SAL "급여", DEPTNO "부서번호"
, CASE WHEN K.DEPTNO = 10 THEN (SELECT COUNT (*)+ 1
FROM EMP
WHERE SAL > K.SAL AND DEPTNO = 10)
WHEN K.DEPTNO = 20 THEN (SELECT COUNT (*)+ 1
FROM EMP
WHERE SAL > K.SAL AND DEPTNO = 20)
WHEN K.DEPTNO = 30 THEN (SELECT COUNT (*)+ 1
FROM EMP
WHERE SAL > K.SAL AND DEPTNO = 30)
ELSE 0
END "부서내 급여등수"
, (SELECT COUNT(*) +1
FROM EMP
WHERE SAL > K.SAL) "전체급여등수"
FROM EMP K
ORDER BY DEPTNO;
------------------------------------------------------
SELECT E.ENAME "사원명", E.SAL "급여", E.DEPTNO "부서번호"
, (SELECT COUNT (*) + 1
FROM EMP
WHERE SAL > E.SAL AND DEPTNO = E.DEPTNO) "부서내급여등수"
, (SELECT COUNT (*) + 1
FROM EMP
WHERE SAL > E.SAL) "전체급여등수"
FROM EMP E
ORDER BY DEPTNO;
/*
CLARK 2450 10 2 6
KING 5000 10 1 1
MILLER 1300 10 3 9
JONES 2975 20 3 4
FORD 3000 20 1 2
ADAMS 1100 20 4 12
SMITH 800 20 5 14
SCOTT 3000 20 1 2
WARD 1250 30 4 10
TURNER 1500 30 3 8
ALLEN 1600 30 2 7
JAMES 950 30 6 13
BLAKE 2850 30 1 5
MARTIN 1250 30 4 10
*/
SELECT ENAME, SAL
FROM EMP
WHERE DEPTNO = 20;
-- ○ EMP 테이블을 대상으로 다음과 같이 조회될 수 있도록 쿼리문을 구성
---------------------------------------------------------------------------
-- 사원명 부서번호 입사일 급여 부서내입사별급여누적
---------------------------------------------------------------------------
-- :
-- SMITH 20 1980-12-17 800 800
-- JONES 20 1981-04-02 2975 3775
-- FORD 20 1981-12-03 3000 6775
-- :
---------------------------------------------------------------------------
SELECT ENAME "사원명"
, DEPTNO "부서번호"
, HIREDATE "입사일"
, SAL "급여"
, (SELECT SUM(SAL)
FROM EMP
WHERE DEPTNO = E.DEPTNO
AND E.HIREDATE >= HIREDATE) "부서내입사별급여누적"
FROM EMP E
ORDER BY DEPTNO, HIREDATE
;
-------- ↑나 ↓선생님 ------------
SELECT E1.ENAME "사원명", E1.DEPTNO "부서번호"
, E1.HIREDATE "입사일", E1.SAL "급여"
, (SELECT SUM(E2.SAL)
FROM EMP E2
WHERE E2.DEPTNO = E1.DEPTNO
AND E1.HIREDATE >= E2.HIREDATE) "부서내입사별급여누적"
FROM EMP E1
ORDER BY 2, 3;
/*
CLARK 10 1981-06-09 2450 2450
KING 10 1981-11-17 5000 7450
MILLER 10 1982-01-23 1300 8750
SMITH 20 1980-12-17 800 800
JONES 20 1981-04-02 2975 3775
FORD 20 1981-12-03 3000 6775
SCOTT 20 1987-07-13 3000 10875
ADAMS 20 1987-07-13 1100 10875
ALLEN 30 1981-02-20 1600 1600
WARD 30 1981-02-22 1250 2850
BLAKE 30 1981-05-01 2850 5700
TURNER 30 1981-09-08 1500 7200
MARTIN 30 1981-09-28 1250 8450
JAMES 30 1981-12-03 950 9400
*/
-- ○ EMP테이블을 대상으로
-- 입사한 사원의 수가 가장 많았을 때의
-- 입사년월과 인원수를 조회할 수 있도록 쿼리문을 구성한다.
SELECT *
FROM EMP;
------------------------------
---- 입사년월 인원수
------------------------------
SELECT "입사년월"
, "인원수"
FROM TBL_EMP;
SELECT TO_CHAR(HIREDATE, 'YYYY-MM') "입사년월"
, COUNT(*) "인원수"
FROM EMP S
GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM')
HAVING COUNT(*) = (SELECT MAX(COUNT(*))
FROM EMP
GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM'));
728x90