DATABASE
[오라클] 그룹함수(ROLLUP(), GROUPING(), CUBE()) / HAVING절 / 중첩 그룹함수 / 분석함수
온풀
2022. 3. 12. 00:06
20220224_01_scott.sql / 오라클 8일 차
ROLLUP()
--○ 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 NVL2(DEPTNO, TO_CHAR(DEPTNO), '모든부서') "부서번호", SUM(SAL) "급여합"
FROM EMP
GROUP BY ROLLUP(DEPTNO);
--==>>
/*
10 8750
20 10875
30 9400
모든부서 29025
*/
SELECT *
FROM TBL_EMP;
SELECT NVL(TO_CHAR(DEPTNO), '모든부서') "부서번호", SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY ROLLUP(DEPTNO);
--==>>
/*
10 8750
20 10875
30 9400
모든부서 8700
모든부서 37725
*/
SELECT NVL2(DEPTNO, TO_CHAR(DEPTNO), '모든부서') "부서번호", SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY ROLLUP(DEPTNO);
--==>>
/*
10 8750
20 10875
30 9400
모든부서 8700
모든부서 37725
*/
GROUPING()
--○ 위에서 조회한 해당 내용을
/*
10 8750
20 10875
30 9400
인턴 8700
모든부서 37725
*/
-- 이와 같이 조회될 수 있도록 쿼리문을 구성한다.
--※ 참고
SELECT GROUPING(DEPTNO) "GROUPING", DEPTNO "부서번호", SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY ROLLUP(DEPTNO);
--※ 힌트
SELECT CASE GROUPING(DEPTNO) WHEN 0 THEN '단일부서'
ELSE '모든부서'
END "부서번호"
, SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY ROLLUP(DEPTNO);
--==>>
/*
단일부서 8750
단일부서 10875
단일부서 9400
단일부서 8700
모든부서 37725
*/
-- 수업 풀이
SELECT CASE GROUPING(DEPTNO) WHEN 0 THEN TO_CHAR(DEPTNO)
ELSE '모든부서'
END "부서번호"
, 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 테이블을 대상으로
-- 다음과 같이 조회될 수 있도록 쿼리문을 구성한다.
/*
---------------------------
성별 급여합
---------------------------
남 XXXXXX
여 XXXXXX
모든사원 XXXXXX
---------------------------
SELECT T.성별 "성별"
, 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
여 32100
(null) 54000
*/
SELECT CASE GROUPING(T.성별) WHEN 0 THEN T.성별
ELSE '모든사원'
END "성별"
, 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
여 32100
모든사원 54000
*/
--○ TBL_SAWON 테이블을 대상으로
-- 다음과 같이 조회될 수 있도록 연령대별 인원수를 확인할 수 있는
-- 쿼리문을 구성한다.
/*
----------------------
연령대 인원수
----------------------
10 X
20 X
40 X
50 X
전체 XX
----------------------
*/
-- 수업 풀이 -------------------------------------------------------------------
-- 방법 1. → INLINE VIEW를 두 번 중첩
-- 나이
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 0
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 -1
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 0
END "연령대"
FROM
(
SELECT 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 -1
END "나이"
FROM TBL_SAWON
) T1
)T2
GROUP BY ROLLUP(T2.연령대);
-- 방법 2. → INLINE VIEW를 한 번만
--연령대
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 -1
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번 부서 모든 직종의 급여합 -- CHECK~!!!
20 ANALYST 6000 -- 20번 부서 ANALYST 직종의 급여합
20 CLERK 1900 -- 20번 부서 CLERK 직종의 급여합
20 MANAGER 2975 -- 20번 부서 MANAGER 직종의 급여합
20 (null) 10875 -- 20번 부서 모든 직종의 급여합 -- CHECK~!!!
30 CLERK 950 -- 30번 부서 CLERK 직종의 급여합
30 MANAGER 2850 -- 30번 부서 MANAGER 직종의 급여합
30 SALESMAN 5600 -- 30번 부서 SALESMAN 직종의 급여합
30 (null) 9400 -- 30번 부서 모든 직종의 급여합 -- CHECK~!!!
(null) (null) 29025 -- 모든 부서 모든 직종의 급여합 -- CHECK~!!!
*/
CUBE()
--○ 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;
--> CUBE() 를 사용한 결과와 같은 조회 결과
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;
--> ROLLUP() 을 사용한 결과와 같은 조회 결과
SELECT *
FROM TBL_EMP
ORDER BY HIREDATE;
HAVING절
--○ EMP 테이블에서 부서번호가 20, 30 인 부서를 대상으로
-- 부서의 총 급여가 10000 보다 적을 경우만 부서별 총 급여를 조회한다.
SELECT *
FROM EMP;
SELECT DEPTNO, SUM(SAL)
FROM EMP
WHERE DEPTNO IN (20, 30)
GROUP BY DEPTNO;
--==>>
/*
30 9400
20 10875
*/
SELECT DEPTNO, SUM(SAL)
FROM EMP
WHERE DEPTNO IN (20, 30)
AND SUM(SAL) < 10000
GROUP BY DEPTNO;
--==>> 에러 발생
-- (ORA-00934: group function is not allowed here) -- 그룹 함수를 이곳에서 쓸 수 없다~
SELECT DEPTNO, SUM(SAL)
FROM EMP
WHERE DEPTNO IN (20, 30)
GROUP BY DEPTNO
HAVING SUM(SAL) < 10000;
--==>> 30 9400
-- 프롬 조건절에 의해
-- 웨어절에 해당하는 것만 메모리에 올리는 거
SELECT DEPTNO, SUM(SAL)
FROM EMP
GROUP BY DEPTNO
HAVING SUM(SAL) < 10000
AND DEPTNO IN (20, 30); --> 여기에 쓸 수 있지만, 웨어절에 쓰는 게 더욱 효율적
--==>> 30 9400
--> 얘보다 위에 것이 더 효율적이다!!!
중첩 그룹함수 / 분석함수
-- 그룹함수... NULL을 제외하고 ... 연산 수행
-- 그룹 함수는 2 LEVEL 까지 중첩해서 사용할 수 있다. -- 함수 안에 함수 넣기 끝
-- MSSQL 은 이마저도 불가능하다.
SELECT SUM(SAL)
FROM EMP
GROUP BY DEPTNO;
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 의 급여
--==>> 14 -- SMITH 의 급여 등수
SELECT COUNT(*) + 1
FROM EMP
WHERE SAL > 1600; -- ALLEN 의 급여
--==>> 7 -- ALLEN 의 급여 등수
--※ 서브 상관 쿼리(상관 서브 쿼리)
-- 메인 쿼리가 있는 테이블의 컬럼이
-- 서브 쿼리의 조건절(WHERE절, HAVING절)에 사용되는 경우
-- 우리는 이 쿼리문을 서브 상관 쿼리(상관 서브 쿼리)라고 부른다.
SELECT ENAME "사원명", SAL "급여", 1 "급여등수"
FROM EMP;
--==>>
/*
SMITH 800 1
ALLEN 1600 1
WARD 1250 1
JONES 2975 1
MARTIN 1250 1
BLAKE 2850 1
CLARK 2450 1
SCOTT 3000 1
KING 5000 1
TURNER 1500 1
ADAMS 1100 1
JAMES 950 1
FORD 3000 1
MILLER 1300 1
*/
SELECT COUNT(*) + 1
FROM EMP
WHERE SAL > 800; -- SMITH 의 급여
--==>> 14 -- SMITH 의 급여 등수
SELECT ENAME "사원명", SAL "급여", (SELECT COUNT(*) + 1 FROM EMP WHERE SAL > 800) "급여등수"
FROM EMP;
--=>>
/*
SMITH 800 14
ALLEN 1600 14
WARD 1250 14
JONES 2975 14
MARTIN 1250 14
BLAKE 2850 14
CLARK 2450 14
SCOTT 3000 14
KING 5000 14
TURNER 1500 14
ADAMS 1100 14
JAMES 950 14
FORD 3000 14
MILLER 1300 14
*/
SELECT ENAME "사원명", SAL "급여"
, ( SELECT COUNT(*) + 1
FROM EMP
WHERE SAL > E.SAL ) "급여등수"
FROM EMP E;
--==>>
/*
SMITH 800 14
ALLEN 1600 7
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 COUNT(*) + 1
FROM EMP
WHERE SAL > 800; -- SMITH 의 급여
--==>> 14 -- SMITH 의 전체급여등수
SELECT COUNT(*) + 1
FROM EMP
WHERE SAL > 800 -- SMITH 의 급여
AND DEPTNO = 20; -- SMITH 의 부서
--==>> 5 -- SMITH 의 부서내급여등수
SELECT ENAME "사원명", SAL "급여", DEPTNO "부서번호"
, (1) "부서내급여등수"
, (1) "전체급여등수"
FROM EMP;
SELECT ENAME "사원명", SAL "급여", DEPTNO "부서번호"
, (SELECT COUNT(*) + 1
FROM EMP
WHERE SAL > 800
AND DEPTNO = 20) "부서내급여등수"
, (SELECT COUNT(*) + 1
FROM EMP
WHERE SAL > 800) "전체급여등수"
FROM EMP;
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;
--==>>
/*
SMITH 800 20 5 14
ALLEN 1600 30 2 7
WARD 1250 30 4 10
JONES 2975 20 3 4
MARTIN 1250 30 4 10
BLAKE 2850 30 1 5
CLARK 2450 10 2 6
SCOTT 3000 20 1 2
KING 5000 10 1 1
TURNER 1500 30 3 8
ADAMS 1100 20 4 12
JAMES 950 30 6 13
FORD 3000 20 1 2
MILLER 1300 10 3 9
*/
SELECT *
FROM EMP
ORDER BY HIREDATE;
--○ EMP 테이블을 대상으로 다음과 같이 조회될 수 있도록 쿼리문을 구성한다.
------------------------------------------------------------------------------
-- 사원명 부서번호 입사일 급여 부서내입사별급여누적
------------------------------------------------------------------------------
-- :
-- SMITH 20 1980-12-17 800 800
-- JONES 20 1981-04-02 2975 3775
-- FORD 20 1981-12-03 3000 6775
-- :
------------------------------------------------------------------------------
SELECT EMP.ENAME, DEPTNO, HIREDATE, SAL, (1) "부서내입사별급여누적"
FROM SCOTT.EMP
ORDER BY 2, 3;
SELECT E1.ENAME "사원명", E1.DEPTNO "부서번호", E1.HIREDATE "입사일", E1.SAL "급여"
, (1) "부서내입사별급여누적"
FROM EMP E1
ORDER BY 2, 3;
SELECT E1.ENAME "사원명", E1.DEPTNO "부서번호", E1.HIREDATE "입사일", E1.SAL "급여"
, (SELECT SUM(E2.SAL)
FROM EMP E2
WHERE E2.DEPTNO = E1.DEPTNO) "부서내입사별급여누적"
FROM EMP E1
ORDER BY 2, 3;
SELECT E1.ENAME "사원명", E1.DEPTNO "부서번호", E1.HIREDATE "입사일", E1.SAL "급여"
, (SELECT SUM(E2.SAL)
FROM EMP E2
WHERE E2.DEPTNO = E1.DEPTNO
AND E2.HIREDATE <= E1.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
ORDER BY HIREDATE;
----------------------------------
-- 입사년월 인원수
----------------------------------
SELECT TO_CHAR(SYSDATE, 'YYYY-MM') "년월"
FROM DUAL;
--==>> 2022-02
SELECT ENAME, HIREDATE
FROM EMP
ORDER BY 2;
--==>>
/*
SMITH 1980-12-17
ALLEN 1981-02-20
WARD 1981-02-22
JONES 1981-04-02
BLAKE 1981-05-01
CLARK 1981-06-09
TURNER 1981-09-08
MARTIN 1981-09-28
KING 1981-11-17
JAMES 1981-12-03
FORD 1981-12-03
MILLER 1982-01-23
SCOTT 1987-07-13
ADAMS 1987-07-13
*/
SELECT TO_CHAR(HIREDATE, 'YYYY-MM') "입사년월"
, COUNT(*) "인원수"
FROM EMP
GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM');
--==>>
/*
1981-05 1
1981-12 2 ←
1982-01 1
1981-09 2 ←
1981-02 2 ←
1981-11 1
1980-12 1
1981-04 1
1987-07 2 ←
1981-06 1
*/
SELECT TO_CHAR(HIREDATE, 'YYYY-MM') "입사년월"
, COUNT(*) "인원수"
FROM EMP
WHERE COUNT(*) = 2
GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM');
--==>> 에러 발생
-- (ORA-00934: group function is not allowed here)
SELECT TO_CHAR(HIREDATE, 'YYYY-MM') "입사년월"
, COUNT(*) "인원수"
FROM EMP
GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM')
HAVING COUNT(*) = 2 -- 년월로 묶어서 가장 많은 인원 수의 입사 카운트
ORDER BY 1;
--==>>
/*
1981-02 2
1981-09 2
1981-12 2
1987-07 2
*/
SELECT COUNT(*)
FROM EMP
GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM');
--==>>
/*
1
2
1
2
2
1
1
1
2
1
*/
-- 년월로 묶어서 가장 많은 인원 수의 입사 카운트
SELECT MAX(COUNT(*))
FROM EMP
GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM');
--==>> 2
SELECT TO_CHAR(HIREDATE, 'YYYY-MM') "입사년월"
, COUNT(*) "인원수"
FROM EMP
GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM')
HAVING COUNT(*) = (
SELECT MAX(COUNT(*))
FROM EMP
GROUP BY TO_CHAR(HIREDATE, 'YYYY-MM')
)
ORDER BY 1;
--==>>
/*
1981-02 2
1981-09 2
1981-12 2
1987-07 2
*/