SQL의 모든 것/SQL의 실무

오라클 LEFT JOIN, RIGHT JOIN

IT너드남 2024. 4. 19. 00:58
본 글은 oracle 12g 및 실무 영역 기준으로 작성되었음을 알려드립니다.
JOIN IS IIKE PUZZLE



※ 개발을 진행하면서 처음으로 대학교나 학원 및 자격증 공부블 하면서 배웠던 내용을 써먹겠구나! 했는데 사실 가장 헷갈렸던 부분이였다. 필자는 mysql 및 postgresql의 환경만 접했었고, 대규모 프로젝트 경험 또한 없었기 때문에 식은땀이 났던 경험이 생각났다.


1. INNER JOIN
: 개발을 하다보면 실무에서는 INNER JOIN과 LEFT OUTER JOIN을 가장 많이 쓰는 것을 경험할 것이다. 그렇다면 INNER JOIN은 정확히 어떻게 사용할까?

SELECT A.COL1
  FROM TABLE_1 A,
  	   TABLE_2 B
 WHERE A.PK = B.PK;

 

  • 위 코드와 같이 테이블 2개를 조인시킬때, 각 테이블의 PK를 WHERE 절에서 JOIN 시켜주면 된다. 다만, 위 코드처럼 깔끔하게 2개의 테이블로 조인시켜 구성하는 경우는 ODS에서 DIMENSION으로 확장시킬 경우이다. FACT 테이블을 구성하게 되면 최소 3개 이상의 테이블들이 JOIN되어 구성된다.

2. LFET OUTER JOIN

: 위에서 설명했듯이, FACT 테이블을 구성할 땐, 최소 3개 이상의 테이블로 구성하는 경우가 대다수이다. AS-IS에서 1:1로 FACT를 적재하면 가장 좋겠지만, 그렇게 쉬이 진행되는 경우는 크지 않았었다. 아래 코드를 보자.

SELECT A.YMD,
       B.STORE_NM,
       A.SLEM,
       C.RT
  FROM FACT_1 A,
       DIMENSION_1 B,
       FACT_2 C
 WHERE A.STORE_CD = B.STORE_CD
   AND A.YMD = C.YMD(+)
   AND A.STORE_CD = C.STORE_CD(+)
  • 위 코드는 FACT 테이블 2개와 DIMENSION 테이블 1개를 조인시키는 경우이다. A테이블과 B테이블의 PK인 코드값과 A의 테이블과 C테이블의 일자와 코드값을 LEFT OUTER JOIN 하여 추출하는 경우이다.
  • 보통 조인을 하기 전, 메인 테이블을 지정하고 해당 테이블에 각 테이블들을 조인시키는 게 가독성 면에서도 가장 좋고 개발자 본인에게도 헷갈리지 않고 가장 깔끔한 경우이다. 메인 테이블을 지정하지 않고 중구남방으로 조인시키면 해당 값에 대한 검증이 어려울 수 있다.
  • 다만, 해당 코드에서 LEFT OUTER JOIN을 (+)로 표기하였는데, 필자도 초기 LEFT OUTER JOIN은 해당 방식으로 처리하였다. 하지만 개발 후반부 값검증을 진행할 때, 이상하게 값이 안맞는 경우가 있어 ANSI 표준 방식으로 수정해야 했었다. ANSI 표준 방식이 아닌 (+)로 코드를 구성하였을 때, 일부 값들이 누락되는 경우가 있는데 해당 부분은 아직도 원인불명이다. 그렇다면 ANSI 표준 방식은 어떻게 하면 되는지 확인해보자.
SELECT A.YMD,
       B.STORE_NM,
       A.SLEM,
       C.RT
  FROM FACT_1 A
  INNER JOIN DIMENSION_2 B
     ON A.STORE_CD = B.STORE_CD
  LEFT OUTER JOIN FACT_2 C
    ON A.YMD = C.YMD
   AND A.STORE_CD = C.STORE_CD;
  • 위 코드처럼 ON절로 표현되는 것이 ANSI 표준 방식이다. 필자도 개발 후반부에는 LEFT OUTER JOIN이 (+)로 처리 된 코드들을 모두 변경 및 수정하였었다. 여러분들도 oracle로 개발을 진행중이라면 ANSI 표준 방식으로 구성하기를 적극 추천드린다.
SELECT A.DATE,
       A.ST_CD,
       MAX(B.S1_CD) G_CD,
       MAX(B.S2_CD) C_CD,
       MAX(B.S3_CD) A_CD,
       SUM(A.SLEM) SLEM,
       SUM(A.SLEM - A.VAT) S_N_V,
       MAX(C.CTS_N) CTS_N,
       SUM(A.D_A_V) D_A_V,
       NVL(MAX(D.S_A), 0) S_A,
       NVL(MAX(E.C_N_A), 0) C_N_A,
       MAX(F.R_S_Q) R_S_Q,
       MAX(F.R_S_A) R_S_A,
       MAX(G.BROQ) BROQ,
       MAX(G.BROA) BROA,
       MAX(F.BSQ) BSQ,
       MAX(F.BSA) BSA,
       ...
  FROM MRT.TABLE_DI A
  LEFT JOIN COD.TABLE_ST B 
    ON A.ST_CD = B.ST_CD 
  LEFT JOIN MRT.TABLE_STRS C 
    ON A.DATE = C.DATE 
   AND A.ST_CD = C.STR_CD 
   LEFT JOIN (SELECT CR_DATE,
                     ST_CD,
                     SUM(CSA) S_A
  	            FROM FCT.TABLE_CS
               WHERE CR_DATE = /*PARAMETER*/
               GROUP BY CR_DATE, ST_CD) D	          
    ON A.DATE = D.CR_DATE
   AND A.ST_CD = D.ST_CD
  LEFT JOIN (SELECT DATE,
                    ST_CD,
                    SUM(SA) C_N_A
               FROM FCT.TABLE_MAIN 
              WHERE DATE = /*PARAMETER*/
                AND TRDC IN ('2', '3')
              GROUP BY DATE, ST_CD) E
    ON A.DATE = E.DATE 
   AND A.ST_CD = E.ST_CD 
  LEFT JOIN (SELECT BDATE,
                    ST_CD,
                    SUM( CASE WHEN LOC = 'A' THEN Q ELSE 0 END ) AS R_S_Q,
                    SUM( CASE WHEN LOC = 'C' THEN AV ELSE 0 END ) AS R_S_A,
                    SUM( CASE WHEN LOC = 'A' THEN Q ELSE 0 END ) AS BSQ,
                    SUM( CASE WHEN LOC = 'C' THEN AV ELSE 0 END ) AS BSA
               FROM MRT.TABLE_LOC
              WHERE BDATE = /*PARAMETER*/
                AND LOC IN ('A', 'C')
              GROUP BY BDATE, ST_CD) F
    ON A.DATE = F.BDATE
   AND A.ST_CD = F.ST_CD
   (...이하 생략)
  • 위 코드는 필자가 실제 개발했던 쿼리의 샘플이다. A라는 메인 테이블을 기준으로 FACT와 DIMENSION들을 PK에 해당하는 컬럼끼리 조인 처리하여 구성하는 것을 확인할 수 있을 것이다. 
  • 필자가 경험한 사이트들을 토대로 보면 INNER, LEFT OUTER JOIN 이외에 RIGHT OUTER JOIN이나 FULL OUTER JOIN이 쓰이는 경우는 거의 없었다. 다만, FULL OUTER JOIN은 카티션 곱으로 치환하여 사용하기 때문에 본 내용에 관련해서는 조금 더 뒤에서 다루도록 하겠다.