ROWNUM #
정의 #
쿼리 내에서 사용 가능한(실제 칼럼이 아닌) 가상 칼럼이다. ROWNUM에는 숫자 1,2,3,4, ... 의 값이 할당된다. 여기서 n은 ROWNUM과 함께 상용하는 행의 수를 의미한다. ROWNUM의 값은 행에 영구적으로 할당되지 않는다. 테이블의 행은 숫자와 연계되어 참조될 수 없다. 따라서 테이블에서 row5를 요청할 수 없다. 왜냐하면 row5는 존재하지 않기 때문이다.
예제 #
ROWNUM 값은 쿼리의 조건절이 처리되고 난 후 그리고 sort, aggregation이 수행되기 전에 할당된다. 또한 ROWNUM 값은 할당된 이후에만 증가된다. 따라서 아래의 쿼리에서는 행을 반환하지 않는다.
select* from t where ROWNUM >1;
첫 번째 행에 대해 ROWNUM>1의 조건이 참이 아니기 때문에 ROWNUM은 2로 증가하지 않는다. 다시 아래로 생각해보자.
select....ROWNUM from t where group by having order by;
위의 쿼리는 아래와 같은 순서로 처리된다.
- FROM/WHERE 절이 먼저 처리된다.
- ROWNUM이 할당되고 FROM/WHERE 절에서 전달되는 각각의 출력 로우에 대해 증가(increment) 된다.
- SELECT가 적용된다.
- GROUP BY 조건이 적용된다.
- HAVING이 적용된다.
- ORDER BY 조건이 적용된다.
따라서 아래와 같은 쿼리는 에러가 발생한다.
select * from emp where ROWNUM <=5 order by sal desc;
이 쿼리는 가장 높으 연봉을 받는 다섯 명의 직원을 조회하기 위한 Top-N 쿼리로 작성되었다. 하지만 실제로 쿼리는 5개의 레코드를 랜덤하게 반환하게 되고 salary를 기준으로 정렬된다. 이 쿼리를 사용하기 위해서 사용되는 가상 코드는 아래와 같다.
ROWNUM = 1 for x in(select * from emp) loop exit when NOT(ROWNUM<=5)
OUTPUT record to tempROWNUM = ROWNUM+1 end loop SORT TEMP
위에서 볼 수 있듯 처음 5개의 레코드를 가져온 후 바로 sorting이 수행되며 쿼리에서 "WHERE ROWNUM=5"또는 "WHERE ROWNUM>5"와 같은 조건은 의미가 없다. 이는 ROWNUM 값이 조건자 실행 과정에서 행에 할당되며 행이 WHERE 조건에 의해 처리된 이후에만 증가되기 때문이다. 따라서 올바르게 처리된 쿼리는 아래와 같다.
select * from (select * from emp order by sal desc) where ROWNUM<=5;
위 쿼리는 salary를 기준으로 EMP를 내림차순으로 정렬 후 상위의 5개 레코드를(TOP-5 레코드)를 반환한다. 오라클 데이터베이스가 실제로 전체 결과 셋을 정렬하진 않는다.
예제2 #
아래와 같은 쿼리가 있다고 가정해보자.
select.... from .... where order by columns;
또 이 쿼리가 반환하는 데이터가 수천 ~ 수만 개 라고 가정해보자. 하지만 사용자가 실제로 관심 있는 것은 상위 특정 N 개의 결과 값이다. 이 결과를 얻기 위해서는 아래와 같은 방법이 있다.
클라이언트 어플리케이션에서 쿼리를 실행하고 상위 N 개의행만 가져오도록 명령 쿼리를 in-line view로 활용하고 ROWNUM을 이용하여 결과 셋을 제한하는 방법(ex : select * from (query..) where ROWNUM<=N)