본문 바로가기

IT/오라클

[ORACLE] Group by

GROUP BY문은 동일한 값을 가진 데이터를 집계해서 조회하고자 할 때 사용하는 문장이다.
조회, 분석용 SQL에서 가장 많이 사용되는 구문이다.
초급 개발자들을 보면, GROUP BY문을 사용할 때, 이렇게 쓰는건가, 저렇게 쓰는건가 하면서 머뭇거리면서 사용하는 경우가 종종 있다. 절대 그런일이 없도록 심도있게 공부하고 익히기를 바란다.

작성방법
SELECT  T1.REGION_GD
FROM    SQL_TEST.CD_REGION T1
GROUP BY T1.REGION_GD
- 집계할 컬럼을 GROUP BY절 뒤에 적어준다.
- SELECT절에는 GROUP BY에 명시된 컬럼만 사용할 수 있다.
- GROUP BY는 WHERE절과 ORDER BY절 사이에 위치한다.

기초이해
-- 일반 SELECT문장
SELECT  T1.STORE_ID
        ,T1.REGION_CD
FROM    SQL_TEST.MA_STORE T1
-- REGION_CD별 데이터를 GROUP BY
SELECT  T1.REGION_CD
FROM    SQL_TEST.MA_STORE T1
GROUP BY T1.REGION_CD
- 조회되는 데이터의 동일한 값들을 하나의 데이터로 집계하는 문장.
- 아래 그림이 GROUP BY의 기본을 이해하는데 더욱 도움을 줄 것이다.
- GROUP BY REGION_CD를 한 경우 SELECT절에는 STORE_ID를 출력할 수 없다.


여러 컬럼의 집계
- 여러 개의 컬럼에 대해서도 GROUP BY의 사용이 가능하다.
SELECT  T1.REGION_CD
        ,T1.STORE_TP
FROM    SQL_TEST.MA_STORE T1
GROUP BY T1.REGION_CD
        ,T1.STORE_TP
- GROUP BY절 뒤에 집계할 컬럼들을 콤마(,)로 구분해서 여러 개 적어준다.
- SELECT절에 컬럼은 GROUP BY에 적은 컬럼들만 올 수 있으며, 순서는 상관 없다.
SELECT  T1.STORE_TP
        ,T1.REGION_CD
FROM    SQL_TEST.MA_STORE T1
GROUP BY T1.REGION_CD
        ,T1.STORE_TP
ORDER BY T1.REGION_CD
        ,T1.STORE_TP


GROUP BY와 집계함수의 사용
- 집계함수는 GROUP BY에 표시된 컬럼들에 대한 집계한 결과값을 만들어 준다.
- GROUP BY에 표시하지 않은 컬럼도 집계함수를 사용하면 SELECT절에 사용이 가능하다.
- 분석용 리포트에서 합계, 데이터의 건수 또는 최대, 최소값을 구하기 위해 많이 사용한다.
SELECT  T1.CALCU_TP
        ,SUM(T1.ORDER_AMT) SUM_ORDER_AMT
FROM    SQL_TEST.HI_ORDER T1
WHERE   T1.ORDER_YMD LIKE '20091001%'
GROUP BY T1.CALCU_TP
- SUM : 데이터의 합계를 구한다.(숫자형 컬럼에만 가능하다.(
- MAX : 최대값을 구한다.
- MIN : 최소값을 구한다.
- COUNT : 데이터의 건수를 구한다.
- AVG : 평균을 구한다.
SELECT  T1.STORE_ID
        ,SUM(T1.ORDER_AMT) SUM_ORDER_AMT
        ,MAX(T1.ORDER_AMT) MAX_ORDER_AMT
        ,MIN(T1.ORDER_AMT) MIN_ORDER_AMT
        ,COUNT(*) CNT_ORDER
FROM    SQL_TEST.HI_ORDER T1
WHERE   T1.ORDER_YMD LIKE '20091001%'
GROUP BY T1.STORE_ID
- 다음 그림을 통해 집계함수를 이해하도록 하자.


GROUP BY : COUNT와 NULL
- COUNT는 데이터의 건수를 집계하는 함수이다.
- GROUP BY를 사용하지 않고 COUNT(*)만 SELECT절에 표시하면, 테이블의 전체건수를 구할 수 있다.
- COUNT(*) 또는 COUNT(컬럼명)으로 사용할 수 있다.
SELECT  COUNT(*)
        ,COUNT(T1.CARD_NO)
FROM    SQL_TEST.HI_ORDER T1
WHERE   T1.ORDER_YMD LIKE '200901%'
- COUNT(*)의 결과는 37948건, COUNT(T1.CARD_NO)의 결과는 15062건이 나왔다.
  (각자의 환경에 따라 결과값은 틀릴 수 있다. 주목할 건, COUNT(*)와 COUNT(T1.CARD_NO)의 결과가 틀리다는 것이다.)
- COUNT(T1.CARD_NO)의 경우는 CARD_NO가 NULL인 경우는 제외하고 COUNT를 수행한다.
- COUNT(*)는 NULL값의 존재 유무 상관없이 카운트된다, 즉 NULL값도 카운트가 1 증가한다.


GROUP BY : COUNT(DISTINCT)
- COUNT집계 함수 안에 DISTINCT를 사용해서, 데이터의 건수가 아닌, 데이터의 종류 수를 알 수 있다.
SELECT  T1.ORDER_YMD
        ,COUNT(*) ORDER_CNT
        ,COUNT(DISTINCT STORE_ID) ORDER_STORE_CNT
FROM    SQL_TEST.HI_ORDER T1
WHERE   T1.ORDER_YMD LIKE '200901%'
GROUP BY T1.ORDER_YMD
ORDER BY T1.ORDER_YMD
- COUNT(DISTINCT)가 발생되는 경우는 많지 않으며, 성능 악화를 발생시킬 수도 있다.
- 최대한 COUNT(DISTINCT)가 발생되지 않도록 테이블이 설계 되어야 하고,
- 아울러, COUNT(DISTINCT)가 발생되지 않도록 사용자 요구사항을 설득하는 것이 필요하다.
- 마지막으로, 최대한 COUNT(DISTINCT)가 발생되지 않도록 SQL을 작성해야 한다.

GROUP BY : ORDER BY에서 집계 함수의 사용
- ORDER BY절에 집계 함수를 사용한다.
SELECT  T1.REGION_CD
        ,COUNT(*) STORE_CNT
FROM    SQL_TEST.MA_STORE T1
GROUP BY T1.REGION_CD
ORDER BY COUNT(*) DESC
- STORE가 많은 REGION_CD부터 출력된다.
- 실제로 분석 시스템에서 이와 같이 집계된 값 기준으로 정렬하는 경우가 많이 있다.

GROUP BY : HAVING절의 사용
- GROUP BY를 통해 집계된 값에 조회 조건을 줄 수 있다.
- GROUP BY가 완료된 결과에 대한 WHERE절이라고 생각할 수 있다.
SELECT  T1.REGION_CD
        ,COUNT(*) STORE_CNT
FROM    SQL_TEST.MA_STORE T1
WHERE   T1.STORE_TP = 'IND'
GROUP BY T1.REGION_CD
HAVING COUNT(*) <= 20
- WHERE졸울 통해 STORE_TP가 IND인 데이터만 찾아낸다.
- GROUP BY를 통해 REGION_CD별로 데이터를 집계한다.
- HAVING절을 통해 STORE카운트가 20이하인 데이터만 조회한다.
- 다음 두 SQL은 동일한 결과를 만들어 내는 SQL이다.
SELECT  T1.REGION_CD
        ,COUNT(*) STORE_CNT
FROM    SQL_TEST.MA_STORE T1
WHERE   T1.STORE_TP = 'IND'
GROUP BY T1.REGION_CD
HAVING T1.REGION_CD IN ('ATL','L.A');
SELECT  T1.REGION_CD
        ,COUNT(*) STORE_CNT
FROM    SQL_TEST.MA_STORE T1
WHERE   T1.STORE_TP = 'IND'
AND     T1.REGION_CD IN ('ATL','L.A')
GROUP BY T1.REGION_CD
- 위의 SQL들은 WHERE절에 조건을 사용하든, HAVING절에 조건을 사용하든 동일한 결과를 조회하는 SQL이다.
- 이와 같은 경우 HAVING조건이 자동으로 WHERE로 변경된다.
- 하지만, 될수 있는한 조건자체를 WHERE절에 적어주도록 한다.
- 경우에 따라 자동 변경이 안될 수 있기 때문이다.


참조 : http://ryu1hwan.tistory.com/entry/SQL%EB%AC%B8-%EA%B8%B0%EC%B4%88%EC%97%90%EC%84%9C%EC%A4%91%EA%B8%89%EA%B9%8C%EC%A7%80L4GROUP-BY%EB%AC%B8