HAVING 절은 GROUP BY 절에 의해 나오는 나올수 있는 결과에 대해 filtering 해주는 역활을 해준다.
즉 내가 지금까지 생각하던 거와는 달리
group 함수의 결과 컬럼에 대해서만 조건을 주는 게 아니라
결과 SET group by 절에 의해 나올 수 있는 결과 set 에 대해 조건을 줄 수 있다.

다음의 예를 보면 ..
부서별 인원수를 구하는 SQL이다.
SQL> select deptno,count(*) from emp group by deptno;

DEPTNO COUNT(*)
---------- ----------
30 6
20 5
10 3

이 중인 인원수가 4이상인 부서를 출력한다. 즉 group 함수에 의해 계산된 값에 대한 조건이다.
SQL> select deptno,count(*) from emp group by deptno having count(*) > 4;

DEPTNO COUNT(*)
---------- ----------
30 6
20 5

아래의 SQL은 group by 에 의해 만들어진 결과에서 deptno가 20 이상인 부서만 출력한다.
SQL> select deptno,count(*) from emp group by deptno having deptno > 20;

DEPTNO COUNT(*)
---------- ----------
30 6

그러면 group by 절에 의한 결과에 대한 having과 select 절의 where 절은 바꿔 쓸 수 있을까?
아래의 결과를 보면 having deptno > 20 과 where deptno > 20의 결과는 같다. (당연한가?)

SQL> select deptno,count(*) from emp where deptno > 20 group by deptno;

DEPTNO COUNT(*)
---------- ----------
30 6

그러나 having 절에 의한 조건은 filter 처리로 계산된 결과에서 특정 조건만을 걸러내고 있으나,
where 절의 경우 access 처리로 scan의 범위를 줄이고 있음을 알 수 있다.

SQL> select deptno,count(*) from emp group by deptno having deptno > 20;

------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 6 | 3 (34)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | HASH GROUP BY | | 2 | 6 | 3 (34)| 00:00:01 |
| 3 | INDEX FAST FULL SCAN| EMP_IDX04 | 449 | 1347 | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("DEPTNO">20)

SQL> select deptno,count(*) from emp where deptno > 20 group by deptno;

----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 6 | 1 (0)| 00:00:01 |
| 1 | SORT GROUP BY NOSORT| | 2 | 6 | 1 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMP_IDX03 | 193 | 579 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("DEPTNO">20)

queyr의 결과는 동일하나 access 하는 범위 자체가 틀리니 이에 대한 주의가 필요하다.
당연히 access 범위를 줄일 수 있는 조건은 where 절에 기술하는 것이 유리할 듯 !!

근데, 테스트 하다보니 아래처럼 수행해도 결과가 잘 나오더군요.
select는 count를 했으나 having에는 sum으로 조건을 주어도 결과가 잘 나오네요.

SQL> select deptno,count(*) from emp group by deptno having sum(sal) > 10000;

DEPTNO COUNT(*)
---------- ----------
20 5

Execution Plan
----------------------------------------------------------
Plan hash value: 3110987654

----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 28 | 13 (8)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | HASH GROUP BY | | 4 | 28 | 13 (8)| 00:00:01 |
| 3 | TABLE ACCESS FULL| EMP | 449 | 3143 | 12 (0)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(SUM("SAL")>10000)

그럼 group by에 의한 수행 결과에 대해 조건을 주는 것이 아니라
group by에 의해 나올 수 있는 결과에 대해 조건을 줄 수 있다는 거군요..

count(*)와 sum(sal)은 operation 자체가 다른데, 이걸 다 계산하고 있다는 건가?
아니면 having에 있는 sum()이 query 수행시 참조되는 건가?

"The HAVING clause is closely associated with the GROUP BY clause. The HAVING clause is used to put a filter on the groups created by the GROUP BY clause. If a query has a HAVING clause along with a GROUP BY clause, the result set will include only the groups that satisfy the condition specified in the HAVING clause."

네, having 절에 있는 group operation도 참조되는 게 맞습니다.. ^^

SQL> select deptno from emp group by deptno having sum(sal) > 10000;

DEPTNO
----------
20

'먹고살기 > Oracle' 카테고리의 다른 글

오라클함수 TO_CHAR (datetime)  (0) 2011.04.22
[Oracle] distinct, rowid 중복제거, 최신 데이터 하나만 가져오기  (0) 2011.04.15
select구문  (0) 2011.04.06
오라클 유저 생성  (0) 2011.04.05
시간 날짜 계산  (0) 2011.04.05