Analytic Functions
데이터의 통계적인 자료를 분석하고 집계하는 기능이다. 실무에서도 많이 사용되어지고 있다.
COUNT(), OVER(), OVER( PARTITION BY ), OVER( ORDER BY )
샘플 데이터
CREATE TABLE school(
student_id NUMBER NOT NULL, -- 학번
dep_name VARCHAR2(100) NOT NULL, -- 학과명
grade NUMBER NOT NULL, -- 학년
score NUMBER NOT NULL, -- 성적
PRIMARY KEY(student_id)
);
INSERT INTO school VALUES(101, '컴퓨터공학과', 2, 2);
INSERT INTO school VALUES(102, '컴퓨터공학과', 3, 3);
INSERT INTO school VALUES(103, '경영학과', 2, 2);
INSERT INTO school VALUES(104, '경영학과', 2, 3);
INSERT INTO school VALUES(105, '경영학과', 3, 4);
INSERT INTO school VALUES(106, '전자공학과', 3, 2);
SELECT * FROM school;
[결과]
집계함수
SELECT COUNT(), MIN(), MAX(), AVG(), STDDEV() ...
데이터의 갯수, 최솟값, 최댓값, 평균, 표준편차 등을 집계하여 보여주는 함수이다.
SELECT COUNT(*), MIN(score), MAX(score), AVG(score) FROM school
[결과]
COUNT(data) : data의 갯수
MIN(data) : data의 최솟값
MAX(data) : data의 최댓값
AVG(data) : data의 평균값
표와 같이 모든 데이터의 집계 결과를 하나의 행으로 보여주고 있다.
필요하다면, GROUP BY를 사용할 수 있다.
SELECT dep_name, COUNT(*), MIN(score), MAX(score), AVG(score)
FROM school
GROUP BY dep_name
[결과]
모든 데이터의 집계가 아닌 그룹별 집계 데이터를 보여준다.
하지만 데이터는 모든 데이터대로 나오고 집계함수의 결과는 결과대로 보여주는 즉, 모든 row를 보고싶을 때 사용하는 기능이 OVER이다.
OVER
전체 데이터와 집계함수의 결과를 보여준다.
SELECT S.*, COUNT(*) OVER () AS total_count
FROM school S
[결과]
모든 데이터에 총 갯수를 보여준다.
다른 집계함수도 보여줄 수 있다.
SELECT S.*,
COUNT(*) OVER() AS total_count,
MIN(score) OVER() AS mins,
MAX(score) OVER() AS maxs,
AVG(score) OVER() AS avgs,
SUM(score) OVER() AS sums
FROM school S
[결과]
모든 데이터와 집계함수의 결과를 보여준다.
하지만 경우에 따라 그룹별 집계함수의 결과를 알고싶거나 그룹별 집계함수의 누적된 값을 알고 싶을 때가 있다. 이 때 PARTITION BY와 ORDER BY를 사용하면 된다.
OVER( PARTITION BY ), OVER( ORDER BY )
1. PARTITION BY
그룹영역을 지정하여 그룹별로 집계함수의 값을 보여준다.
SELECT S.*,
COUNT(*) OVER(
PARTITION BY dep_name
) AS school_per_depName,
SUM(score) OVER(
PARTITION BY dep_name
) AS score_per_depName
FROM school S
[결과]
OVER() 안에 PARTITION BY를 추가하고 그룹핑하려는 속성을 지정해주면 결과와 같이 그 그룹의 집계함수 결과만을 보여준다.
이 맥락에선 dep_name을 기준으로 그룹핑한 후 각 그룹의 갯수(COUNT)와 합계(SUM)을 모든 레코드에서 보여주고 있다.
2. ORDER BY
통계 결과의 누적된 값을 보여준다.
SELECT S.*,
COUNT(*) OVER(
ORDER BY student_id
) AS total_count,
SUM(score) OVER(
ORDER BY student_id
) AS total_sum
FROM school S
[결과]
OVER() 안에 ORDER BY를 추가하고 누적되는 컬럼을 명시해주어야 한다. 그래서 ORDER BY 다음은 반드시 UNIQUE한 속성을 명시해 주어야한다. 그렇지 않으면 누적이 되지 않는 현상을 볼 수 있다.
이 맥락에선 COUNT의 누적값이라 +1씩 올라가는 것을 볼 수 있다.
또한 누적된 합계(TOTAL_SUM)는 모든 컬럼의 점수(SCORE)의 누적된 값을 볼 수 있다.
이 맥락과 같이 누적된 값을 보고 싶을 때에는 반드시 ORDER BY 다음에 UNIQUE한 속성을 명시해야 한다.
3. PARTITION BY · ORDER BY
PARTITION BY와 ORDER BY 기능 둘 다 사용 시
SELECT S.*,
COUNT(*) OVER(
PARTITION BY dep_name
ORDER BY student_id
) AS student_per_depName,
SUM(score) OVER(
PARTITION BY dep_name
ORDER BY student_id
) AS score_per_depName
FROM school S
[결과]
각 그룹별로 누적된 값을 볼 수 있다.
Filtering
WHERE 조건에 집계함수를 사용하여 필터를 할 수 있는지에 대해 알아보자.
SELECT dep_name, COUNT(*) FROM school
WHERE COUNT(*) OVER( PARTITION BY dep_name ) >= 2
dep_name을 그룹핑 한 COUNT의 갯수가 2개 이상인 데이터들만 보고싶을 때 이러한 쿼리문을 실행하면
'그룹 함수는 허가되지 않습니다' 라는 오류를 볼 수 있다.
이유는 간단하다.
쿼리문 실행순서는 FROM -> WHERE -> GROUP BY -> SELECT 이다.
즉, FROM절에서 테이블에 있는 값을 기준으로 WHERE절에서 체크를 하는데 현재 COUNT(*) OVER( PARTITION BY dep_name)은 SELECT절에서 실행하는 쿼리문이기 때문에 WHERE절에서 찾지 못하는 것이다.
쉽게 말해 그룹함수는 SELECT절에서 사용하는 것인데 실행순서상 SELECT절은 WHERE절보다 늦게 읽혀지기 때문에 WHERE절에서는 그룹함수를 사용할 수 없는 것이다.
이럴 경우에는 2가지 방법이 있다.
1. GROUP BY를 사용하여 미리 그룹화 해서 나온 HAVING절에 그룹함수를 넣는다.
2. FROM절에 SELECT구문을 한번 더 감싼 다음 사용한다.
1.
SELECT dep_name, COUNT(*)
FROM school
GROUP BY dep_name
HAVING COUNT(*) >= 2
그룹함수를 HAVING절에서 사용한다.
[결과]
2.
SELECT *
FROM (
SELECT S.*, COUNT(*) OVER( PARTITION BY dep_name) dep_count
FROM school S
)
WHERE dep_count >= 2
FROM절에서 그룹함수를 사용한 테이블을 만든 후 WHERE절에서 조건처리를 해준다.
[결과]
쿼리문 실행 순서를 생각해보면 당연한 결과이다.
필터 처리는 이런 식으로 해주면 된다.
마무리
분석 · 집계 함수인 Analytic Functions에 대하여 공부해 보았다.
실무에서 자주 쓰이는 기능이라 제대로 확실하게 배우고 넘어가면 좋을 것 같다.
다음 시간에는 더욱 중요한 기능들인 ROWNUM, RANK, LAG, FIRST VALUE... 등을 배우려고 한다.
'Database > Oracle' 카테고리의 다른 글
[Oracle] 오라클 ANSI JOIN vs Oracle JOIN (0) | 2022.11.20 |
---|---|
[Oracle] Oracle LISTAGG 함수 (List Aggregate) (0) | 2022.11.18 |
[Oracle] Analytic Functions 3 (분석 · 집계 함수) (0) | 2022.11.18 |
[Oracle] Analytic Functions 2 (분석 · 집계 함수) (0) | 2022.11.17 |
[Oracle] Oracle 계층형 쿼리(Hierarchical Query) - START WITH, CONNECT BY (0) | 2022.11.09 |