반응형

Join은 sql의 시작과 끝

실무를 하다보면 결국 join (inner join)과 left join 을 가장 많이 쓰게 되는데 실제 데이터와 쿼리를 보면서 어떤식으로 결과가 나오는지 확인해본다. 

데이터는 Join을 이해하기 쉽도록 포인트 적립과 사용에 대한 데이터를 예제로 사용해본다.

 

데이터 준비 

- write (DDL) 쿼리가 안되는 환경을 고려해서 다음과 같이 데이터를 넣는다. 

상황 : AA, BB 두명의 유저가 있고 포인트를 쌓거나 사용하고 있으며 각각 get_point, use_point에 로그를 남긴다. . 

point 테이블 : 간단하게 idx(index, Primary Key값, 고유번호를 의미하는 컬럼)만 넣은 테이블

get_point 테이블 : 포인트 적립 (p_idx, idx, uid, point) , p_idx로 point.idx와 엮을 수 있다.

use_point 테이블 : 포인트 사용 (p_idx, idx, uid, point) , p_idx로 point.idx와 엮을 수 있다.

*원래 idx , p_idx , uid, point 순서가 더 자연스러운데 중간에 수정하다보니.. 글을 전체 수정하기 어려워서 이대로 감.

with point as (
select     1  IDX union all
select     2  union all
select     3  union all
select     4  union all
select     5  union all
select     6  union all
select     7  union all
select     8  union all
select     9  union all
select     10  union all
select     11  union all
select     12  union all
select     13  union all
select     14  union all
select     15  union all
select     16 
)

,get_point as (
select    1 p_IDX, 1  IDX,    'AA'  UID,   1000 POINT union all
select    2 ,    2    ,     'AA'   ,      1500 union all
select    3 ,    3    ,     'BB'   ,      1000 union all
select    4 ,    4    ,     'AA'   ,      1000 union all
select    6,     5    ,     'BB'   ,      2000 union all
select    7,     6    ,     'AA'   ,      500 union all
select    10,    7    ,     'BB'   ,      5000 union all
select    11,    8    ,     'AA'   ,      10000 union all
select    15,    9    ,     'BB'   ,      3000 union all
select    16,   10    ,     'AA'   ,      5000 
)

,use_point as (
select   5 p_IDX,  1  IDX,    'AA'  UID,   -1500 POINT union all
select   8,      2    ,       'AA'   ,     -200 union all
select   9,      3    ,       'BB'   ,      -100 union all
select   12,     4    ,     'AA'   ,      -100 union all
select   13,     5    ,     'BB'   ,      -2800 union all
select   14,     6    ,     'AA'   ,      -500 
)

 

 

데이터 확인

  • point 테이블
select * from point p

 

  •  get_point 테이블
select * from get_point gp

 

 

  • use_point 테이블
select * from use_point up

 

 

inner join 결과

이때, 만약 전체를 join 한다면?

select * from point p 
join get_point gp on gp.p_idx = p.idx
join use_point up on up.p_idx = p.idx

=> 아무것도 나오지 않는다.

 

 

호옥..시 point.idx별로 join 이 되어서 전체 적립/사용 테이블이 나오길 기대했나? 

아니다. 그걸 보기 위해서는 Left join 으로 처리해야한다. 

 

 

left join 결과

select * from point p
Left join get_point gp on p.idx=gp.p_idx 
left join use_point up on p.idx=up.p_idx

이렇게 했더니 원하는 것을 볼 수 있게 되었다. 

 

case when 사용해서 정리하기

위 쿼리의 결과로 나온 테이블은 뭔가 정리가 안 되어 있음. 원하는것에 아직 한발 부족함. 

그럴때는 case when을 사용함. 

먼저 위의 Left join 두개 사용한 쿼리를 With 문으로 서브쿼리로 만들어 주고, 해당 테이블을 다시 사용하면서 case 문을 이용하는 방식

,tbl as (
select p.idx, 
      gp.idx gp_idx, gp.p_idx gp_p_idx,  gp.uid gp_uid, gp.point gp_point, 
      up.idx up_idx, up.p_idx up_p_idx,  up.uid up_uid, up.point up_point
from point p 
left join get_point gp on p.idx=gp.p_idx 
left join use_point up on p.idx=up.p_idx 
)


select tbl.idx,
      case when gp_idx is not null then gp_idx else up_idx end gu_idx, 
      case when gp_idx is not null then gp_point else up_point end point,
      case when gp_idx is not null then gp_uid else up_uid end uid
 from tbl

그럼 요렇게 나온다. 

반응형

+ Recent posts