ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SQL BOOSTER - GROUP BY와 ROLLUP
    DataBase/SQL 2024. 6. 2. 18:37

     

    프로젝트를 수행하는데 최소한의 SQL임! 잘 알아두자 

     

     

    1. GROUP BY 

     

    • 데이터를 그룹화하는 문법이다. (같은 값을 가진 데이터끼리 모으는 것을 의미)
    • 중복된 값이 제거된 결과로 나오면서, 집계함수를 사용한다.
    SELECT T1.ORD_DT, T1.PAY_TP,SUM(T1.ORD_AMT)ORD_AMT
    FROM T_ORD T1
    WHERE T1.ORD_ST = 'COMP'
    GROUP BY T1.ORD_DT, T1.PAY_TP
    ORDER BY T1.ORD_DT, T1.PAY_TP;
    • T1.ORD_DT로 1차 그룹화 후 T1.PAY_TP로 2차 그룹화 (주문일시, 지불유형별 주문 금액 합계)

    출처: https://thebook.io/006977/0175/

    • 자주 쓰는 집계함수는 다음과 같다.
      • SUM,COUNT,MIN,MAX
      • OVER 절과 함께 사용하는 SUM,LEAD,LAG와 같은 분석함수는 집계함수와 다른 개념이다. 
      • 집계함수는 GROUP BY 없이도 단독 사용 가능(단, 집계함수를 사용하지 않은 컬럼 동시 SELECT 불가)
        • 모든 ROW 데이터에 대해 집계함수 적용

     

    1. 규칙 1 GROUP BY에 사용한 컬럼만 SELECT 절에서 그대로 사용 가능하다.
    2. 규칙 2 GROUP BY에 사용하지 않은 컬럼은 SELECT절에서 집계함수를 사용해야한다. 

     

    1.2 GROUP BY 컬럼 변형 

    • GROUP BY에 컬럼을 정의할 대 컬럼을 변형할 수 있다. 변형을 위해 TO_CHAR, TO_DATE와 같은 오라클 기본 함수 
    • CASE와 같은 치환 문법 사용할 수 있다. 
    • 또한 문자와 문자 결합 혹은 산술연산도 할 수 있다
    SELECT ORD_ST, 
        CASE WHEN ORD_AMT >= 5000 THEN 'HIGH'
             WHEN ORD_AMT >= 3000 THEN 'Middle Order'
             ELSE 'Low Order' END ORD_AMT_TP, COUNT(*) ORD_CNT
    FROM T_ORD
    GROUP BY ORD_ST, 
         CASE WHEN ORD_AMT >= 5000 THEN 'HIGH'
              WHEN ORD_AMT >= 3000 THEN 'Middle Order'
              ELSE 'Low Order' END
     ORDER BY 1,2;
    • CASE 처리를 통해 GROUP BY를 하고 있다.
      • ORDER BY에서 사용한 컬럼 + 데이터 명  SELECT에서 사용한 컬럼 + 데이터 명 일치해야한다. (규칙 1)
    • 1회성 쿼리에선 주문금액을 CASE로 나누는 위와 같은 SQL이 괜찮지만, 운영할 때는 지양하자 
      • ORD_AMT의 기준이 변경되면 SQL을 모두 변경해야하기 때문이다. 
    SELECT TO_CHAR(ORD_DT,'YYYYMM') ORD_YM, PAY_TP, COUNT(*) ORD_CNT
    FROM T_ORD
    WHERE ORD_ST = 'COMP'
    GROUP BY TO_CHAR(ORD_DT,'YYYYMM'), PAY_TP
    ORDER BY TO_CHAR(ORD_DT,'YYYYMM'), PAY_TP;
    •  위는 주문일시를 YYYYMM형태로 변경해서 주문년월별 주문 건수 조회하는 SQL이다. 

     

    1.3 집계함수에서 CASE문 사용하기 

     

    집계함수 괄호 안에서도 CASE문을 사용할 수도 있다. 

    이를 사용하면, CASE 조건에 따라 집계를 수행할 수 있다. 

    SELECT TO_CHAR(ORD_DT,'YYYYMM') ORD_YM, SUM(CASE WHEN PAY_TP = 'BANK' THEN 1 END) BANK_PAY_CNT,
    SUM(CASE WHEN PAY_TP ='CARD' THEN 1 END) CARD_PAY_CNT
    FROM T_ORD
    WHERE ORD_ST = 'COMP'
    GROUP BY TO_CHAR(ORD_DT,'YYYYMM')
    ORDER BY TO_CHAR(ORD_DT,'YYYYMM');
    • 주문년월별로 계좌이체 건수와 카드결제 건수'를 조회하는 SQL이다. 
      • CASE에 따라 sum에 1을 넘겨서 계산하는 방식은 매우 자주 사용하니 잘 봐두자

    201701 PAY_TP CARD, BANK -> 집계함수 -> 201701 PAY_TP BANK (1) PAY_TP CARD(1) 

    SELECT PAY_TP,
            COUNT(CASE WHEN TO_CHAR(ORD_DT,'YYYYMM') = '201701' THEN 'X' END) ORD_CNT_1701
            , COUNT(CASE WHEN TO_CHAR(ORD_DT,'YYYYMM') = '201702' THEN 'X' END) ORD_CNT_1702
            , COUNT(CASE WHEN TO_CHAR(ORD_DT,'YYYYMM') = '201703' THEN 'X' END) ORD_CNT_1703
            , COUNT(CASE WHEN TO_CHAR(ORD_DT,'YYYYMM') = '201704' THEN 'X' END) ORD_CNT_1704
            , COUNT(CASE WHEN TO_CHAR(ORD_DT,'YYYYMM') = '201705' THEN 'X' END) ORD_CNT_1705
            , COUNT(CASE WHEN TO_CHAR(ORD_DT,'YYYYMM') = '201706' THEN 'X' END) ORD_CNT_1706
            , COUNT(CASE WHEN TO_CHAR(ORD_DT,'YYYYMM') = '201707' THEN 'X' END) ORD_CNT_1707
            
            FROM T_ORD
            WHERE ORD_ST = 'COMP'
            GROUP BY PAY_TP
            ORDER BY PAY_TP;
            
            
    // 혹은 아래와 같은 방식 사용 가능
    SELECT t1.PAY_TP, MAX(CASE WHEN t1.ORD_YM='201701' THEN t1.ORD_CNT END) ORD_CNT_1701
           ,MAX(CASE WHEN t1.ORD_YM='201702' THEN t1.ORD_CNT END) ORD_CNT_1702
           ,MAX(CASE WHEN t1.ORD_YM='201703' THEN t1.ORD_CNT END) ORD_CNT_1703
           ,MAX(CASE WHEN t1.ORD_YM='201704' THEN t1.ORD_CNT END) ORD_CNT_1704
           ,MAX(CASE WHEN t1.ORD_YM='201705' THEN t1.ORD_CNT END) ORD_CNT_1705
           
           FROM (
            SELECT t2.PAY_TP, TO_CHAR(t2.ORD_DT,'YYYYMM') ORD_YM,COUNT(*) ORD_CNT
            FROM T_ORD t2
            WHERE t2.ORD_ST = 'COMP'
            GROUP BY t2.PAY_TP, TO_CHAR(t2.ORD_DT,'YYYYMM')
            )t1
      GROUP BY t1.PAY_TP;
      
      -- CARD 201701 73
         CARD 201702 153
      -- PAY  201701 67
         PAY  201702 79 -> 인라인뷰 결과 
     -- MAX를 사용한 이유는 인라인뷰 COUNT 결과 가져올 때 집계함수 사용해야하는데 마땅한게 없어서 쓴듯

    • 건수를 시간 순서대로 표현했다
      • 이렇게 가로에 시간 속성을 보여주는 것이 굉장히 흔한 편이다. 
      • 물론 컬럼을 로우로 변환하는 PIVOT 기능을 지원하는 BI툴이 많음으로, GROUP BY와 CASE 조합 사용할 일은 많지는 않다.

    1.4 COUNT 집계함수

     

    • COUNT는 다른 집계함수와 다르게 조금 더 살펴볼 필요가 있다. 
    1. COUNT(칼럼)는 NULL은 0으로 카운트한다. (칼럼 확인) 
    2. COUNT(*)는 로우를 COUNT로 (로우 갯수 확인)
    3. SELECT절에서 DISTINCT를 중복제거 가능하다 COUNT(DISTINCT 컬럼)
      1. COUNT(DISTINCT T1.ORD_ST || '-'|| T1.PAY_TP) 두개 이상 컬럼 DISTINCT 처리 
      2. 혹은 인라인뷰를 사용해야 두 개 이상의 컬럼에 사용할 수 있다.
        1. 한 번이라도 로그인이 있는 고객수
        2. 한 번이라도 사용 기록이 있는 메뉴 수 
        3. 한 번이라도 판매가 이루어진 아이템 수 
    -- 각각 SELECT ~ EXISTS 혹은 DISTICT를 사용하여 
    SELECT COUNT(*)
    FROM 고객 t1
    WHERE EXISTS(
            SELECT * 
            FROM 로그인 A
            WHERE A.고객ID = T1.고객ID
            );
                          
                          
    SELECT COUNT(DISTINCT T1.고객ID)
    FROM 로그인 T1

     


    2. HAVING 

     

    HAVING절은 GROUP BY가 수행된 결과 집합에 조건을 줄 때 사용한다. WHERE절 기능 수행 

    HAVING은 AND나 OR을 이용해 여러 조건을 동시에 사용할 수도 있다. 

    HAVING에서는 GROUP BY에서 정의한 내용은 그대로 사용할 수 있으나, GROUP BY에 없는 내용은 집계함수 처리 후에 사용해야한다. 

    SELECT T1.CUS_ID,T1.PAY_TP,SUM(T1.ORD_AMT) ORD_TTL_AMT
    FROM T_ORD T1
    GROUP BY T1.CUS_ID, T1.PAY_TP
    HAVING T1.ORD_ST ='COMP' -- ERROR
    • WHERE절에 사용하거나, T1.ORD_ST에 집계함수를 적용하면 사용할 수 있다.
    • 인라인 뷰를 사용해 처리할 수도 있다
    SELECT T0.*
    FROM (
    	SELECT T1.CUS_ID,T1.PAY_TP,SUM(T1.ORD_AMT) ORD_TTL_AMT
        FROM T_ORD T1
        WHERE T1.ORD_ST = 'COMP'
        GROUP BY T1.CUS_ID, T1.PAY_TP
        )T0
    WHERE T0.ORD_TTL_AMT >= 10000
    ORDER BY T0.ORD_TTL_AMT ASC;
    • 그룹으로 묶고, WHERE절 처리 

    https://www.yes24.com/Product/Goods/82818767

     

    SQL BOOSTER - 예스24

    SQL BOOSTER는 프로젝트 성공을 위한 SQL 필독서다. 이 책은 마치 프로젝트를 진행하는 순서처럼 구성되어 있다. 프로젝트 투입을 위해 필요한 SQL 기술을 설명하고, 성능 테스트를 위해 필요한 기술

    www.yes24.com

     

Designed by Tistory.