ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SQLBOOSTER - INNER JOIN
    DataBase/SQL 2024. 6. 4. 23:27

     

    INNER-JOIN 이란

     

    • 이너 조인은 조인 조건을 만족하는 데이터만 결합하여 결과를 내보낸다. (T1.CUS_ID = T2.CUS_ID)
    • WHERE 절에서 사용하는 조건은 필터 조건과 조인 조건 두 가지가 있다. 
    • FROM 절에 사용된 테이블이 두 개 이상이면 필터 조건과 조인 조건이 동시에 있을 수 있다.
    SELECT T1.COL_1, T2_COL_1
    FROM (
    	SELECT 'A' COL_1 FROM DUAL UNION ALL
        SELECT 'B' COL_1 FROM DUAL UNION ALL
        SELECT 'A' COL_1 FROM DUAL 
    )T1,
    (
    	SELECT 'A' COL_1 FROM DUAL UNION ALL
        SELECT 'B' COL_1 FROM DUAL UNION ALL
        SELECT 'B' COL_1 FROM DUAL UNION ALL
        SELECT 'D' COL_1 FROM DUAL 
    )T2
    
    WHERE T1.COL_1 = T2.COL_1;

    • T1.COL_1의 속성값이 T2.COL_1의 속성 값과 하나씩 비교하면서 같은 것을 추림 
    • 조인 조건을 만족하는 데이터만 결합되어 결과에 나올 수 있다.
      • 이때 조인 조건은 같다 뿐만 아니라 다른 조건식도 사용할 수 있다.
    • 한 건과 M(Many)건이 조인되면 M건의 결과가 나온다.
      • T1의 B 한 건이 T2의 B 두 건과 결합해 두 건의 결과가 나왔다.

     


    INNER_JOIN 처리 과정 

     

    SELECT T1.CUS_ID, T1.CUS_GD, T2.ORD_SEQ, T2.CUS_ID, T2.ORD_DT
    FROM M_CUS T1, T_ORD T2
    WHERE T1.CUS_ID = T2.CUS_ID
    AND T1.CUS_GD='A'
    AND T2.ORD_DT >= TO_DATE('20170101','YYYYMMDD')
    AND T2.ORD_DT < TO_DATE('20170201','YYYYMMDD');

     

     

    1. M_CUS에서 CUS_GD가 A인 데이터만 찾는다 (필터 조건 처리)
    2. M_CUS의 첫번째 로우인 CUS_1과 같은 CUS_ID가 T_ORD에 있는지 검색 
      1. T_ORD에 CUS_1이 존재하지만 ORD_DT가 2017년 2월이므로 조인에 실패 (이는 필터 조건 2017 1월 주문만 처리하는 조건 때문이다.) [조인조건]
    3. M_CUS의 세 번째 로우인 CUS_3과 같은 CUS_ID T_ORD에 있는지 검색한다. 
    4. ..이를 반복 

     

    필터조건을 먼저 처리하고 난 뒤에 이를 만족한 데이터에 한해서 조인에 참여한다. 

    또한, 1:M으로 조인하면, 결과는 M의 값이 나온다는 점도 다시 한번 알아 두자 

     

    SQL에서 두 조인의 순서를 완전히 뒤바꿔도 같은 결과가 나올 것이다.

    INNER 조인은 순서를 바꾼다고 결과가 달라지지 않는다. (성능에는 영향이 있을 수도 있다)

     

    *조인 조건을 보통 =으로 두어 같은 값 끼리만 조인한다고 생각할 수 있는데, inner  join은 같은 값을 가진 데이터를 비교하는게 아니라, 조인 조건을 만족하는 데이터 간 조인이다.

     


     

    여러 테이블의 조인 

     

    • 여러 테이블의 조인을 잘하기 위해선 조인을 테이블과 테이블 간의 연결이 아니라, 데이터와 데이터 집합 간의 연결이라고 생각을 바꾸는 것이 좋다. 
      • 테이블 자체를 데이터 집합으로 볼 수 있다.
      • WHERE절의 필터 조건을 거친 결과를 데이터 집합이라 할 수 있다.
      • 두 개의 데이터 집합이 조인된 결과는 새로운 하나의 데이터 집합이다. 
    • A테이블과 B테이블을 조회하면, 물리적인 테이블을 합치는 느낌보다 두개의 테이블이 연결된 새로운 데이터 집합인 것
    • 아무리 많은 테이블을 조인해도 한 번의 조인에는 두 개의 데이터 집합만 사용되고, INNER JOIN은 JOIN순서를 바꾼다고 결과가 달라지지 않는다. 

    잘 못 작성한 조인 (M:1:M조인)

     

    조인을 사용하다 중복된 데이터 때문에 강제로 DISTINCT를 사용하는 경우가 있다. 이는 잘못작성한 SQL이다.

     

    정확한 조인을 구사하기 위해 다음을 고려해보자 

     

    • 1:1 관계 조인 = 1건의 결과 발생 
    • 1:M 관계 조인 = M건의 결과 발생 
    • M*M관계 조인 = M*M건의 결과 발생 

    다대다 관계에서 조인은 OLTP환경에서 거의 발생할 일이 없다 (사실 없어야한다.) 

     

    보통 세 개의 테이블을 M:1:M의 관계일 때 조인에서 실수가 발생한다.

     

    (EX 1은 중심 테이블이고 M인 테이블은 각각 1의 키 값을 참조하는 실적테이블)

     

    SELECT T1.CUS_ID, T1.CUS_NM,COUNT(DISTINCT T2.ITM_ID ||'-'|| TO_CHAR(t2.evl_lst_no))EVAL_CNT
    ,COUNT(DISTINCT T3.ORD_SEQ)ORD_CNT
    FROM M_CUS T1, T_ITM_EVL T2, T_ORD T3
    WHERE T1.CUS_ID = T2.CUS_ID
    AND T1.CUS_ID = T3.CUS_ID
    AND T1.CUS_ID = 'CUS_0023'
    AND T2.EVL_DT >= TO_DATE('20170301','YYYYMMDD')
    AND T2.EVL_DT <  TO_DATE('20170401','YYYYMMDD')
    AND T3.ORD_DT >=  TO_DATE('20170301','YYYYMMDD')
    AND T3.ORD_DT < TO_DATE('20170401','YYYYMMDD')
    GROUP BY T1.CUS_ID,T1.CUS_NM;

     

    • 문법상 문제는 없지만 COUNT(DISTINCT)를 사용해서 총 결과를 강제로 맞힌 SQL이므로 좋은 방식은 아니다. 
    • DISTINCT사용하지 않고 SQL을 작동시키면 아이템 평가 횟수와 주문 횟수가 모두 6건인데, 이를 각각 2건, 3건으로 맞추기 위해 DISTINCT를 사용했다.

     

    해결방법 

     

    1 UNION ALL 사용 

     

    SELECT T1.CUS_ID,MAX(T1.CUS_NM) CUS_NM, SUM(T1.EVL_CNT) EVL_CNT, SUM(T1.ORD_CNT) ORD_CNT
    FROM(
        SELECT T1.CUS_ID, MAX(T1.CUS_NM) CUS_NM, COUNT(*) EVL_CNT, NULL ORD_CNT
        FROM M_CUS T1, T_ITM_EVL T2
        WHERE T1.CUS_ID = T2.CUS_ID
        AND T2.CUS_ID = 'CUS_0023'
        AND T2.EVL_DT >= TO_DATE('20170301','YYYYMMDD')
        AND T2.EVL_DT < TO_DATE('20170401','YYYYMMDD')
        GROUP BY T1.CUS_ID,T1.CUS_NM 
        UNION ALL 
    SELECT T1.CUS_ID,MAX(T1.CUS_NM) CUS_NM,NULL EVL_CNT,COUNT(*) ORD_CNT
    FROM M_CUS T1, T_ORD T3
    WHERE T1.CUS_ID = T3.CUS_ID
    AND T3.CUS_ID = 'CUS_0023'
    AND T3.ORD_DT >= TO_DATE('20170301','YYYYMMDD')
    AND T3.ORD_DT < TO_DATE('20170401','YYYYMMDD')
    GROUP BY T1.CUS_ID, T1.CUS_NM
    )T1
    GROUP BY T1.CUS_ID;
    • UNION ALL 컬럼을 맞춰주기 위해 NULL ORD_CNT 처럼 속성을 표현할 수 있다. 
    • 각각 조인 후에 결과를 UNION ALL로 결합 
    SELECT T1.CUS_ID,MAX(T1.CUS_NM) CUS_NM, SUM(T4.EVL_CNT) EVL_CNT, SUM(T4.ORD_CNT) ORD_CNT
    FROM M_CUS T1,
        (
        SELECT T2.CUS_ID, COUNT(*) EVL_CNT, NULL ORD_CNT
        FROM  T_ITM_EVL T2
        WHERE T2.CUS_ID = 'CUS_0023'
        AND T2.EVL_DT >= TO_DATE('20170301','YYYYMMDD')
        AND T2.EVL_DT < TO_DATE('20170401','YYYYMMDD')
        GROUP BY T2.CUS_ID 
        UNION ALL 
    SELECT T3.CUS_ID, NULL EVL_CNT,COUNT(*) ORD_CNT
    FROM  T_ORD T3
    WHERE T3.CUS_ID = 'CUS_0023'
    AND T3.ORD_DT >= TO_DATE('20170301','YYYYMMDD')
    AND T3.ORD_DT < TO_DATE('20170401','YYYYMMDD')
    GROUP BY T3.CUS_ID
    )T4
    WHERE T1.CUS_ID = T4.CUS_ID
    GROUP BY T1.CUS_ID;
    • M_CUS를 맨 밖에 한번만 사용했다 (성능이 쫌 더 낫다)

     

    2. 1:1:1로 조인 

     

    • 나머지 M인 테이블들을 GROUP BY을 통해 1로 만든 후 1:1:1조인을 수행하는 것이다. 
    SELECT T1.CUS_ID,T1.CUS_NM,T2.EVL_CNT,T3.ORD_CNT
    FROM M_CUS T1,(
        SELECT T2.CUS_ID,COUNT(*) EVL_CNT
        FROM T_ITM_EVL T2
        WHERE T2.CUS_ID = 'CUS_0023'
        AND T2.EVL_DT >= TO_DATE('20170301','YYYYMMDD')
         AND T2.EVL_DT < TO_DATE('20170401','YYYYMMDD')
         GROUP BY T2.CUS_ID)T2
         ,(
        
        SELECT T3.CUS_ID,COUNT(*) ORD_CNT
        FROM T_ORD T3
        WHERE T3.CUS_ID = 'CUS_0023'
        AND T3.ORD_DT >= TO_DATE('20170301','YYYYMMDD')
         AND T3.ORD_DT < TO_DATE('20170401','YYYYMMDD')
         GROUP BY T3.CUS_ID)T3
         
       WHERE T1.CUS_Id = T2.CUS_ID
       AND T1.CUS_ID = T3.CUS_ID
       AND T1.CUS_ID ='CUS_0023';

     

    • 1로만드는 GROUP BY 기준은 1테이블과 M테이블을 조인할때 사용하는 컬럼을 기준으로 생각해보자

     

    • 이너 조인 주의점
      • 모든 데이터가 각각 존재할 때 조인이 가능하다 
        • 무조건 값이 나오게 하려면 OUTTER 조인을 사용하자 
      • 주요 마스터 하나에 다른 테이블 (M:1:M)관계일때는 주의를 기울이자. 
        • 무조건 성공적인 조인 조건을 적을 것이 아니라, 데이터 건수가 어떻게 변하는지 상상해보고 조인을 작성하자

     

     


    참고자료 

     

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

     

    SQL BOOSTER - 예스24

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

    www.yes24.com

     

     

     

Designed by Tistory.