[Oracle] 오라클 KEEP 사용법 (최저, 최고 순위 값)
- 데이터베이스/오라클
- 2022. 2. 8.
오라클에서 KEEP 키워드를 사용하면 행 그룹(GROUP BY) 내에서 최고 또는 최고 순위 행으로 집계를 할 수 있다. 그룹별로 MAX 또는 MIN 수치 값은 쉽게 표시할 수 있지만, MAX에 해당하는 행의 값 중에서 특정 텍스트 값을 같이 표시하기 위해서는 서브 쿼리를 사용하는 방법이 많이 사용된다. 그러나 KEEP 키워드를 사용하면 한 번의 쿼리문으로 최저 또는 최고에 해당하는 행의 값들을 쉽게 가져올 수 있다. KEEP 키워드는 GROUP BY 절 또는 OVER 절과 함께 사용해야 한다.
KEEP을 처음 사용한다면 순위 함수(DENSE_RANK)를 알고 있으면 조금 더 쉽게 이해할 수 있다.
기본 사용법
KEEP (DENSE_RANK LAST) - 마지막 순위 값 가져오기
SELECT job
, MAX(sal) KEEP(DENSE_RANK LAST ORDER BY sal) AS sal_last
, MAX(ename) KEEP(DENSE_RANK LAST ORDER BY sal) AS ename_last
FROM emp
WHERE job IN ('MANAGER', 'SALESMAN')
GROUP BY job
직군(job) 별로 DENSE_RANK를 사용하여 연봉(sal) 순위로 정렬하여 직군별 마지막 직원의 직원명과 연봉을 표시하는 예제이다. (연봉이 낮은 순에서 높은 순(ASC)으로 정렬되었음)
MAX(sal)의 값은 KEEP을 사용하지 않아도 쉽게 가져올 수 있지만, KEEP를 사용하지 않고 MAX(sal)에 해당하는 직원명을 가져오기 위해서는 한 번의 쿼리문으로 어렵다.
DENSE_RANK 함수를 사용하여 직군(job) 별로 순위를 부여하여 직군별 마지막 순위 값을 가져와서 표시한다. 마지막 순위의 값이 1행만 존재하기 때문에 MAX 함수는 큰 의미는 없다. 마지막 순위의 값이 여래행인 경우 MAX 함수에 의해서 값이 변동될 수 있다.
KEEP (DENSE_RANK FIRST) - 처음 순위 값 가져오기
SELECT job
, MAX(sal) KEEP(DENSE_RANK FIRST ORDER BY sal) AS sal_first
, MAX(ename) KEEP(DENSE_RANK FIRST ORDER BY sal) AS ename_first
FROM emp
WHERE job IN ('MANAGER', 'SALESMAN')
GROUP BY job
직군(job) 별로 DENSE_RANK를 사용하여 연봉(sal) 순위로 정렬하여 직군별 첫 순위 직원의 직원명과 연봉을 표시하는 예제이다. (연봉이 낮은 순에서 높은 순(ASC)으로 정렬되었음)
직군이 MANAGER인 경우 첫 순위의 행이 1개이기 때문에 값이 변동 없이 표시되지만, 직군이 SALESMAN인 경우 첫 순위의 값이 2개의 행이라서 MAX 함수에 의해서 2개의 값 중 MAX 값이 표시된다.
MAX(ename) → 'WARD'
MIN(ename) → 'MARTIN'
순위가 중복되는 경우 정확하지 않는 값이 표시될 수 있으므로, 정렬 조건을 세분화하여 순위가 겹치지 않게 하는 것이 좋다.
활용 예제
다양한 집계 함수에서 사용 가능
SELECT job
, MAX(sal) KEEP(DENSE_RANK FIRST ORDER BY sal) AS keep_max
, MIN(sal) KEEP(DENSE_RANK FIRST ORDER BY sal) AS keep_min
, SUM(sal) KEEP(DENSE_RANK FIRST ORDER BY sal) AS keep_sum
, COUNT(sal) KEEP(DENSE_RANK FIRST ORDER BY sal) AS keep_count
FROM emp
WHERE job IN ('MANAGER', 'SALESMAN')
GROUP BY job
MIN, MAX 함수 외에도 다양한 집계 함수에서 사용 가능하다. 상황에 맞는 집계 함수와 함께 사용하면 된다.
OVER 절과 함께 사용 가능 (GROUP BY 절 없이)
SELECT ename
, job
, sal
, MAX(sal) KEEP(DENSE_RANK LAST ORDER BY sal) OVER(PARTITION BY job) AS sal_last
, MAX(ename) KEEP(DENSE_RANK LAST ORDER BY sal) OVER(PARTITION BY job) AS ename_last
FROM emp
WHERE job IN ('MANAGER', 'SALESMAN')
ORDER BY job, sal
OVER 절과 함께 사용하면 GROUP BY 절 없이도 사용할 수 있다.