※오라클은 NULL을 가장 큰값으로 간주한다.
(ORACLE 9i 까지는 NULL이 가장 작은값이었다.)
MSSQL 은 NULL을 가장 작은 값으로 간주한다.
✏️그룹 함수의 가장 큰 특징
처리해야 할 데이터들 중 NULL이 존재한다면(포함되어 있다면)
이 NULL은 제외한 상태로 연산을 수행한다는 것이다.
즉,NULL은 연산의 대상에서 제외된다.
--○SUM() 합
-- EMP 테이블을 대상으로 전체 사원들의 급여 총합을 조회한다.
SELECT SUM(SAL)
FROM EMP;
--29025 총합
SELECT SUM(COMM) --NULL+300+500.... (x)
FROM EMP;
--==>2200 NULL을 제외하고 연산한다.
--○COUNT() 행(레코드)의 갯수 조회 -> 데이터가 몇 건인지 확인...
SELECT COUNT(ENAME)
FROM EMP;
--==>>14
SELECT COUNT(COMM)
FROM EMP;
--==>>4 NULL을 세지 않음
SELECT COUNT(*)
FROM EMP;
--특정 컬럼을 명시하지않고 보통 이렇게 쓴다.
--○AVG() 평균 반환
SELECT AVG(SAL) "COL"
,SUM(SAL) / COUNT(SAL) "COL2"
FROM EMP;
--2073.214285714285714285714285714285714286
--2073.214285714285714285714285714285714286
SELECT AVG(COMM) "COL1"
,SUM(COMM) / COUNT(COMM) "COL2"
FROM EMP;
SELECT VARIANCE(SAL), STDDEV(SAL)
FROM EMP;
--==>>1398313.87362637362637362637362637362637
--==>>1182.503223516271699458653359613061928508
SELECT POWER(STDDEV(SAL),2) "COL1" --표준 편차 제곱
,VARIANCE(SAL) "COL2"
FROM EMP;
--1398313.87362637362637362637362637362637
--1398313.87362637362637362637362637362637
SELECT SQRT(VARIANCE(SAL)) "COL1"
, STDDEV(SAL) "COL2"
FROM EMP;
--==>>
/*
1182.503223516271699458653359613061928508
1182.503223516271699458653359613061928508
*/
-- 최대값 / 최소값 반환
SELECT MAX(SAL) "COL1"
,MIN(SAL) "COL2"
FROM EMP;
--5000 800
SELECT ENAME, SUM(SAL)
FROM EMP;
--ORA-00937: not a single-group group function
ENAME는 여러행이나 SUM은 그룹함수로서 한개의 행만을 반환한다.
이를위해 사용하는것이 GROUP BY다.
SELECT DEPTNO "부서번호", SUM(SAL) "급여합"
FROM TBL_EMP
GROUP BY DEPTNO
ORDER BY DEPTNO;
/*
10 8750
20 10875
30 9400
8700 --부서번호가 NULL인 사원들의 급여합
*/
ELECT 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이다
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
*/
--GROUPING 반환값이 1인 것은 ROLLUP이 수행된것
위의 내용을 CASE WHEN NVL을 통해
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 테이블을 대상으로
--다음과 같이 조회될 수있도록 쿼리문 작성
----------------------------
성별 급여합
-----------------------------
남 xxxx
여 xxxxx
모든사원 xxxx
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.성);
or
SELECT NVL(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.성별);
--○TBL_SAWON 테이블을 대상으로
--다음과 같이 조회될 수있도록 쿼리문 작성
/*
----------------------------
연령대 인원수
-----------------------------
10 x
20 x
30 x
50 x
전체 16
*/
인라인쿼리
SELECT NVL(T2.나이대,'전체') "연령대" --CASE GROUPING(T.나이대) WHEN 0 TO_CHAR(T.나이대) ELSE '전체' END
,COUNT(*) "인원"
FROM(
SELECT CASE WHEN T1.나이>=50 THEN '50'
WHEN T1.나이>=30 THEN '30'
WHEN T1.나이>=20 THEN '20'
WHEN T1.나이>=10 THEN '10'
ELSE '확인필요'
END "나이대"
FROM(
SELECT CASE WHEN SUBSTR(JUBUN,7,1) IN ('1','2') THEN TO_NUMBER(TO_CHAR(SYSDATE,'YYYY')) - (TO_NUMBER(SUBSTR(JUBUN,1,2)) + 1899)
ELSE TO_NUMBER(TO_CHAR(SYSDATE,'YYYY')) - (TO_NUMBER(SUBSTR(JUBUN,1,2)) + 1999)
END "나이"
FROM TBL_SAWON
)T1
)T2
GROUP BY ROLLUP(나이대);
or
----------------나이대 붙이기 GROUPING(숫자형) GROUP BY ROLLUP(숫자형) 이라는걸 기억하자.
SELECT CASE GROUPING(T1.나이) WHEN 0 THEN T1.나이||'대'
ELSE '전체' END "나이대" ,COUNT(*)
FROM(
SELECT CASE WHEN SUBSTR(JUBUN,7,1) IN ('1','2') THEN TRUNC(EXTRACT(YEAR FROM SYSDATE)-(TO_NUMBER(SUBSTR(JUBUN,1,2))+1899),-1)
WHEN SUBSTR(JUBUN,7,1) IN ('3','4') THEN TRUNC(EXTRACT(YEAR FROM SYSDATE)-(TO_NUMBER(SUBSTR(JUBUN,1,2))+1999),-1)
ELSE -1
END "나이"
FROM TBL_SAWON
)T1 --T1
GROUP BY ROLLUP(T1.나이);
View
CREATE OR REPLACE VIEW VIEW_SAWONTEMP
AS
SELECT CASE WHEN T.나이>=50 THEN '50'
WHEN T.나이>=30 THEN '30'
WHEN T.나이>=20 THEN '20'
WHEN T.나이>=10 THEN '10'
ELSE '확인필요'
END "나이대"
FROM(
SELECT CASE WHEN SUBSTR(JUBUN,7,1) IN ('1','2') THEN TO_NUMBER(TO_CHAR(SYSDATE,'YYYY')) - (TO_NUMBER(SUBSTR(JUBUN,1,2)) + 1899)
ELSE TO_NUMBER(TO_CHAR(SYSDATE,'YYYY')) - (TO_NUMBER(SUBSTR(JUBUN,1,2)) + 1999)
END "나이"
FROM TBL_SAWON
)T;
이후
SELECT NVL(나이대,'전체') "나이대", COUNT(나이대)
FROM VIEW_SAWONTEMP
GROUP BY ROLLUP(나이대);
--ROLLUP은 하나만 묶을수 있는 애가 아니다.
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 CLERK 1900
20 MANAGER 2975
20 (null) 10875 --20번 부서 모든 직종의 급여합
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
30 (null) 9400 --30번 부서 모든 직종의 급여합
(null) (null) 29025 --모든 부서 모든 직종의 급여합
2개묶었을땐 이렇게 사용한다.
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
*/
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
*/
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
*/