1. 분석 함수 종류를 살펴보고 활용하자
2. join을 살펴보고 구현해보자
============================================================================
분석함수를 사용하게 된 이유
- RDBS 상에서 컬럼과 컬럼 연산, 비교, 연결은 쉬운 반면
행과 행간의 관계를 정의하거나 비교, 연산하는 것을 하나의 SQL로 처리하기 힘든점을 해결할려고
- 그 전에는 프로그램을 작성, 인라인 뷰를 이용해서 복잡한 SQL문 작성
- 분석함수를 도입해서 행간의 연산을 원할하게 연동한다. 단, 중첩사용은 불가능
서브쿼리에는 사용 가능
[형식]
SELECT Analytic_Function(arguments) OVER
([PARTITION By 절] [ORDER BY 절] [WINDOWING 절])
FROM 테이블명;
- Analytic_Function : AVG, COUNT, LAG, LEAD, MAX, MIN, RANK, RATIO_TO_REPORT
ROW_NUMBER, SUM 등
arguments 0 ~ 3개 까지만 올 수 있다.
*는 COUNT(*)만 허용. DISTINCT는 해당 집계 함수가 허용할 때만 가능
- OVER : 해당 함수가 쿼리 결과 집합에 따라서 적용되는 지시어이다.
FROM, WHERE, GROUP BY, HAVING 이후에 계산된다.
SELECT, ORDER BY 구문 뒤에 사용할 수 있다.
- PARTITION By : 쿼리 결과를 < expr_list > 별로 그룹핑한다. 생략시에는 하나의 그룹으로 리턴
- ORDER BY : ORDER BY < expr_list > [ (ASC | DESC), (NULL FIRST | LAST) ]
< expr_list >에서는 별칭이나 숫자를 사용할 수 없다.
- WINDOWING : ROWS, RANGE가 일단 핵심
ROWS는 물리적인 단위(ROW위치)고 RANGE는 논리적인 단위(ROW값)이다.
ROWS[RANGE] BETWEEN start_point AND end_point
- start_point : 그룹별 시작점을 의미 UNBOUNDED PRECEDING, CURRENT ROW,
value_expr PRECEDING or value_expr FOLLOWING 이 올 수 있다.
- end_point : 그룹별 시작점을 의미 UNBOUNDED FOLLOWING, CURRENT ROW,
value_expr PRECEDING or value_expr FOLLOWING 이 올 수 있다.
분석함수의 장점
- JOIN이나 프로그램의 OVERHEAD를 줄임
(QUERY SPEED의 향상된 SELF-JOIN, 절차적 로직으로 표현하는 것을 NATIVE SQL에서
바로 적용할 수 있도록 JOIN이나 프로그램의 OVERHEAD를 줄임)
- 간결한 SQL로 복잡한 분석 작업을 수행가능 (유지보수가 간편하고 생산성 향상)
- 이해 및 활용이 용이 (기존 SQL - syntax를 그대로 쓰기 때문에 ANSI SQL로 채택된다)
============================================================================
Ranking Family 특징
- 대상집합에 대해서 특정 컬럼들을 기준으로 순위나 등급을 부여한다.
- 오름차순, 내림차순 가능
- NULL 은 순위의 가장 처음 또는 마지막으로 강제 처리된다.
- Rank function은 각 PARTITOIN마다 초기화 된다.
- 순위 또는 등급은 GROUP BY, CUBE, ROLLUP절 마다 초기화가 된다.
RANK() : 각 로우마다 순위를 매긴다.
P -> O -> 1부터 시작하여 동일한 값은 동일한 순위를 가지고,
동일한 순위의 수만큼 다음 순위는 건너 뛴다.
DENSE_RANK() : RANK와 다르게 동률있는 수만큼 순위를 미루지 않는다 ex) 1, 1, 2등
CUME_DIST() : CUMULATIVE DISTRIBUTION FUNCTION
- PARTITION 나누어진 블럭별로 각 ROW를 ORDER BY에 명시된 순서대로 정렬한 후
그룹별 상대적인 위치(누적된 분산정보)를 구한다
- 상대적인 위치는 구하고자 하는 값보다 작거나 같은 값을 가진 ROW수를
그룹 내의 전체 ROW수로 나눈 것을 의미한다.
- 결과값의 범위는 0< X <=1 이다.
NTILE() : () 안의 숫자만큼 나눠라
ex) PARTITION 내에 100개의 ROW가 있는데 4개의 BUCKET값을 나누고 싶다. NTILE(4)
=> 1개의 BUCKET 당 25씩 ROW가 배정된다.
ex) 103개의 ROW에 대해서 NTILE(5)를 적용
- 근사치로 배분한 후 남는 값에 대해서 최초 PARTITION부터 한 개씩 배분
ROW_NUMBER()
- PARTITION 내에 ORDER BY 절에 의해 정렬된 순서로 유일한 값을 리턴한다.
- ROWNUM 과는 전혀 상관없다.
============================================================================
WINDOWING : 윈도우 집계함수는 ROW에 대한 집계함수
REPORTING : 한 집합 레벨에 대한 집계 값과 다른 집합 레벨에 대한 집계 값의 비교를 통해
분석하고자 하는 경우
ex) 사원의 급여와 해당 부서의 평균 급여를 비교할 때
사원의 급여를 제외한 부서의 평균 급여를 알고 싶을 때
RATIO_TO_REPORT() : 해당 구간에서 차지하는 비율을 리턴하는 함수
Lead / Lag Family :
- 특정 ROW가 속한 파티션 내에서 상대적 상하 위치에 있는 특정 ROW의 COLUMN 값을
참조하거나 상호 비교할 때 사용하는 함수
============================================================================
예제모음
Q1) 사원테이블에서 사원의 이름, 부서번호, 급여, 급여가 많은 사원으로부터 순위를 조회하자
SELECT ENAME, DEPTNO, SAL, RANK() OVER(ORDER BY SAL DESC) "RANK"
FROM EMP;
SELECT ENAME, DEPTNO, SAL, RANK() OVER(ORDER BY SAL DESC) "RANK"
FROM EMP
ORDER BY 3;
SELECT ENAME, DEPTNO, SAL,
RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) "RANK"
FROM EMP;
Q2) 샘플 테이블 생성, 값 넣기
CREATE TABLE TEST_EMP
AS
SELECT * FROM EMP;
INSERT INTO TEST_EMP (EMPNO, ENAME, SAL, DEPTNO) VALUES ( 111, 111, 3000, 30);
INSERT INTO TEST_EMP (EMPNO, ENAME, SAL, DEPTNO) VALUES ( 222, 222, 3000, 30);
INSERT INTO TEST_EMP (EMPNO, ENAME, SAL, DEPTNO) VALUES ( 333, 333, 3000, 20);
INSERT INTO TEST_EMP (EMPNO, ENAME, SAL, DEPTNO) VALUES ( 444, 444, 3000, 20);
Q3)
SELECT ENAME, DEPTNO, SAL,
RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) "RANK"
FROM TEST_EMP;
Q4) TEST_EMP 테이블에서 DENSE_RANK() PARTITON, ORDER BY로 구해보자
SELECT ENAME, DEPTNO, SAL,
DENSE_RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) "RANK"
FROM TEST_EMP;
Q5) 20번 부서 사원의 이름, 봉급, 누적분산 정보를 조회하자
SELECT ENAME, SAL, CUME_DIST() OVER ( ORDER BY SAL DESC) "상위 몇%"
FROM TEST_EMP
WHERE DEPTNO = 20;
Q6) 사원의 봉급을 기준으로 4등급으로 분류하자
SELECT ENAME, SAL, NTILE(3) OVER(ORDER BY SAL DESC)
FROM TEST_EMP;
Q7) 사원번호, 이름, 봉급, 입사일을 조회하는데 순번을 매기자 ( ROW_NUMBER() )
SELECT EMPNO, ENAME, SAL, HIREDATE,
ROW_NUMBER() OVER( ORDER BY SAL DESC, HIREDATE ASC) AS "순번"
FROM TEST_EMP;
SELECT EMPNO, ENAME, SAL, HIREDATE,
ROW_NUMBER() OVER( ORDER BY SAL DESC, HIREDATE ASC) AS "순번"
FROM TEST_EMP
ORDER BY 1;
Q8) 사원의 이름, 부서번호, 급여, 전체급여 합계, 부서별 합계를 리턴
SELECT ENAME, DEPTNO, SAL, SUM(SAL)
FROM EMP; --> 안됨
SELECT ENAME, DEPTNO, SAL,
SUM(SAL) OVER(PARTITION BY DEPTNO) "DEPT SUM",
SUM(SAL) OVER() "TOTAL SUM"
FROM EMP;
Q9) 사원의 이름, 부서번호, 급여, 업무별 급여평균, 해당 업무의 최대 급여를 조회
SELECT ENAME, DEPTNO, JOB, SAL,
AVG(SAL) OVER(PARTITION BY JOB) "AVG JOB",
MAX(SAL) OVER(PARTITION BY JOB) "MAX JOB"
FROM EMP;
Q10) 사원이름, 부서번호, 봉급 합계를 3줄씩 더한 결과, 누적 합계를 구해보자
SELECT ENAME, DEPTNO, SAL,
SUM(SAL) OVER(ORDER BY SAL ROWS BETWEEN 1 preceding AND 1 following) "SUM 1",
SUM(SAL) OVER(ORDER BY SAL ROWS UNBOUNDED PRECEDING) "SUM 2"
FROM TEST_EMP;
2번 줄은 ROWS를 기준으로 위 ROW와 아래 ROW의 SAL을 합친 값
3번 줄은 누적 값
Q11) 사원의 총 월급을 50000으로 증가했을 때 기존 월급 비율로 적용했을 경우
각 사원은 얼마씩 받게되는지 확인해보자
SELECT ENAME, SAL,
RATIO_TO_REPORT(SAL) OVER() AS "비율",
TRUNC( RATIO_TO_REPORT(SAL) OVER() * 50000) AS "받을 급여"
FROM TEST_EMP;
Q12) 사원이름, 부서번호, 봉급, 본인 이전의 봉급 값을 조회 LAG
SELECT ENAME, DEPTNO, SAL,
LAG(SAL, 1, 0) OVER (ORDER BY SAL) AS NET_SAL,
LAG(SAL, 1, SAL) OVER (ORDER BY SAL) AS SAL2
FROM TEST_EMP;
SELECT ENAME, DEPTNO, SAL,
LAG(SAL, 1, 0) OVER (PARTITION BY DEPTNO ORDER BY SAL) AS SAL3
FROM TEST_EMP;
Q13) 사원이름, 부서번호, 봉급, 본인 이전의 봉급 값을 조회 LEAD
SELECT ENAME, DEPTNO, SAL,
LEAD(SAL, 1, 0) OVER (ORDER BY SAL) AS NET_SAL,
LEAD(SAL, 1, SAL) OVER (ORDER BY SAL) AS SAL2
FROM TEST_EMP;
SELECT ENAME, DEPTNO, SAL,
LEAD(SAL, 1, 0) OVER (PARTITION BY DEPTNO ORDER BY SAL) AS SAL3
FROM TEST_EMP;
SELECT ENAME, DEPTNO, SAL,
LAG(SAL, 1, 0) OVER (ORDER BY SAL) AS NET_SAL,
LEAD(SAL, 1, 0) OVER (ORDER BY SAL DESC) AS NET_SAL
FROM TEST_EMP; --> 이게 결과가 같음
'데이터과학자 - 강의 > oracle' 카테고리의 다른 글
210525 oracle - SET, SUBQUERY (0) | 2021.05.25 |
---|---|
210524 oracle - JOIN (0) | 2021.05.25 |
210521 oracle - 함수, 그룹함수, GROUP BY, HAVING, ROLLUP, CUBE, GROUPING (0) | 2021.05.21 |
210518 oracle - SELECT, 기본함수 (0) | 2021.05.18 |
210517 oracle - 설치, select (0) | 2021.05.17 |