이렇게 생각하게 된 데에는 다음가 같은 쿼리의 사용이 주요했다.
select count(1)
from students;
위 쿼리는 항상 0이나 0이 아닌 어떤 값을 반환한다.
그래서 아래처럼 쓰기에 안전하다.
select count(1)
into cnt
from students;
보통의 경우 모든 행의 개수를 알고싶어서 위 쿼리를 쓰지는 않을 것이다. 즉, 조건에 따른 행의 개수를 알고자 할 것이다.
select count(1)
into cnt
from students
where class = '1-1';
혹은
select count(1)
into cnt
from students
group by class
having class = '1-1';
위 두 쿼리는 얼핏보면 같아 보인다. 만약 조건에 맞는 행이 존재한다면 결과는 같을 것이다. 그러나 조건에 맞는 행이 하나도 없다면 엄청난 차이가 난다.
조건에 맞는 행이 없는 경우
첫번째 쿼리는 0을 변수에 집어 넣는다.
그런데 두번째 쿼리는 실행 자체가 실패한다. 왜냐하면 반환되는 행이 하나도 없기 때문이다. NO_DATA_FOUND 에러가 나는 것이다.
자체적으로 분석한 원인은 좀 있다 설명하기로 하고,
그럼 첫번째와 비슷한 다음 쿼리는 어떨까
select count(1)
into cnt
from students
where class = '1-1'
group by class;
이것도 마찬가지로 NO_DATA_FOUND 에러가 난다.
나름대로 생각한 이유는 다음과 같다.
오라클 문서에 보면 group by 가 없는 경우 전체 행에 대해서 aggregate function 을 적용한다고 되어 있다. (If you omit the GROUP BY clause, then Oracle applies aggregate functions in the
select list to all the rows in the queried table or view.)
이 부분이 내가 나름대로 생각한 것이다. group by 가 없으면 전체 행에 대해서 집계를 하는데, 전체 행에서 조건에 맞는 행의 개수를 찾기 때문에 최소한 한개의 행이 반환되는 것이다. 근데 여기서 또 하나의 의문이 생긴다. students 테이블이 아예 비어 있다면 어떤값이 반환될까? ㅎㅎ 이건 또 해봐야 겠다.
그리고 group by 가 있는 경우는 좀 더 명확하다. group by 에 의해 그룹핑 된 행들 각각이 한개의 결과 행을 반환한다고 되어 있는데, 조건에 맞는 그룹이 없다면 아무행도 반환되지 않는것이 당연한 것이다.
이 부분은 헷갈리기 쉬워서 따로 정리해 둔다. 그리고 참고로 NVL로 이런 문제를 피해가면 되지 않냐고 생각할 수 있는데, NO_DATA_FOUND상태에서는 NVL이든 뭐든 적용될 행이 없기 때문에 그런 함수로 문제를 해결 할 수 없다는걸 기억하기 바란다.
students 테이블이 아예 비어 있다면 어떤값이 반환될까? ㅎㅎ 이건 또 해봐야 겠다. 에 대한 부연.
실험해 보니 students 테이블이 비어 있더라도 group by 가 없으면 0을 가진 하나의 행이 반환된다. 아, 이러면 group by 동작에 대해서 일관성있는 설명을 할 수가 없는데.. 좀 더 알아보고 정리해야 겠다.