스프링데이터 + JPA/QueryDSL

15. join on

sdafdq 2023. 11. 29. 13:11

QueryDSL에서 on절은

조인 대상 필터링

연관관계가 없는 테이블 외부 조인

 

이 두가지 역할이 가능하다.

이번엔 주로 left join에 대해서 말 할것이다.

 

먼저, left join이란 from절에 있는 것에 join해서 가져온 것 중 각각 on절에 해당하는 것을 묶어서 나열하는 것이다.

 

from이 중심이다. from의 대상이 되는 것은 다 나열된다.

근데 join해서 가져온 것 중에 from절의 테이블과 연이 없는 것은 그냥 그 열들은 null 상태로 둔다.

 

그래서, 다대일 관계는 from절과 join절의 테이블 위치를 바꿀 시 결과가 다를 수 있다.

from 중심으로, from은 다 나열하고, join해서 가져온 것 중 on의 조건에 맞으면 그 row끼리 붙인다. (근데 이 때 아무래도 일대다 관계 등이면 데이터가 뻥튀기 될 수 있다.)

만약 from 테이블의 데이터 중 join 테이블과 의 데이터 중 엮을 row가 없다면 그냥 그 부분들은 null로 표시 한다.

 

inner join과 다른 점은 join 테이블의 데이터들 중에 on 조건에 맞는 row가 없더라도 그냥 null로 하고 가져온다는거.

inner join은 on해서 맞는 row가 없는 건 그 from 테이블의 데이터 자체를 가져오지 않음.

 

 

여튼, on절로 left join 해 오면서, join 대상 테이블을 필터링 할 수 있음.

//회원과 팀을 join하면서, team이름이 teamA인 팀만 조인, 회원은 모두 조회
@Test
public void join_on_filtering(){
    List<Tuple> fetch = query.select(m, t).from(m).leftJoin(m.team, t).on(t.name.eq("teamA")).fetch();
    for (Tuple tuple : fetch) {
        System.out.println("tuple = " + tuple);
    }
}

m와 t를 모두 조회해 오는데, m으로 부터 조회해오며 저 t는 left join 해 온거임. on절을 사용하여 조인 대상 테이블에 필터링 조건을 넣음.

 

기본적으로 

join(from절의테이블의열, join대상테이블의열)

이렇게 하면, 이게 on절로 기본으로 들어감. 그럼 저 뒤에 추가로 쓰는 on은 뭐냐고?

/* select
    member1,
    team 
from
    Member member1   
left join
    member1.team as team with team.name = ?1 */ select
        m1_0.member_id,
        m1_0.age,
        m1_0.team_id,
        m1_0.username,
        t1_0.team_id,
        t1_0.name 
    from
        member m1_0 
    left join
        team t1_0 
            on t1_0.team_id=m1_0.team_id 
            and t1_0.name=?

and 해서 추가로 들어감.

 

 

조인할 대상 특정 조건에 따라 줄여서 가지고 오고 싶을때, on절을 쓴다.

on절에 대한 건 여기로

https://qwefdg3.tistory.com/789

 

그리고 on절이 익숙하지 않다고, 선생님은 inner 조인의 경우에는 그냥 조인할 대상을 줄여올 때 on을 쓰지말고 익숙한 where를 쓰라고 하시는데, 나는 상관없다. 그냥 차라리 테이블 대상으로 줄여올 것이면 on쓰고, 전체 대상을 줄일 것이면 where

 

 

 

이거는 연관관계 있는 left join 이었고, 연관관계 없는 left join. 이거는 자주 씀.

// 회원이름이 팀 이름과 같은 대상 외부조인
@Test
public void join_on_no_relation(){
    em.persist(new Member("teamA"));
    em.persist(new Member("teamB"));
    em.persist(new Member("teamC"));

    List<Tuple> result = query.select(m, t).from(m).leftJoin(t).on(m.username.eq(t.name)).fetch();
    for (Tuple tuple : result) {
        System.out.println("tuple = " + tuple);
    }
}

이런 식으로.

보면 leftJoin쪽이 좀 특이함.

 

원래 보통 join(주가될Q, join할Q)

이렇게 하면, 쿼리를 자동으로

join
    team t1_0 
        on t1_0.team_id=m1_0.team_id

여기까지 완성시켜 준다.

 

조인할 대상 + on 절 까지도 완성해주는 기능이다.

애초에, 저 join 쿼리메서드가

public <P> Q join(     
    com.querydsl.core.types.EntityPath<P> target,
    com.querydsl.core.types.Path<P> alias 
    )

인자로 이렇게 가져올 타겟이랑, 조인 할 별칭을 요구함.

 

그래서 두번째 인자에 조인할 대상이 들어간다는 걸 join() 쿼리메소드가 알기에 join 대상 쿼리를 저렇게 만들어 줄 수 있는거.

 

근데, 

// 회원이름이 팀 이름과 같은 대상 외부조인
@Test
public void join_on_no_relation(){
    em.persist(new Member("teamA"));
    em.persist(new Member("teamB"));
    em.persist(new Member("teamC"));

    List<Tuple> result = query.select(m, t).from(m).leftJoin(t).on(m.username.eq(t.name)).fetch();
    for (Tuple tuple : result) {
        System.out.println("tuple = " + tuple);
    }
}

이게 좀 나중에 하이버네이트 5.1인가? 나온 기능임.

 

원래 인자 2개를 받아야만 했던 join이나 leftJoin을, 하나만 받을 수 있도록 함.

 

이렇게 되면 이제 조인할 대상은 t로 지정을 하지만, 기존에 하던대로 t와 m끼리 on으로 조건을 주지 않음(엔티티 자체로(여기서는 Q인 엔티티 별칭끼리)하면 엔티티.id가 쿼리상에서 치환됨.)

 

단, 꼭 on 조건을 줘야 함.

 

left join이나 join은 on 조건 필수로 쓰게되는데, join에서 인자 하나만 주는 오버라이드는 기존에 인자 두개였던 쿼리상에서 join할 타겟 지정 + on에 첫번째 인자와 두번째 인자의 id끼리 맞추는 걸로 조건지정 이었던 걸

당연히 두번째 인자가 없어지니 join할 타겟지정은 되지만 on에 조건 지정할 다른 인자가 없음.

그래서 타겟지정까지는 되지만, 꼭 on으로 조건을 줘야 함.

 

쿼리

/* select
    member1,
    team 
from
    Member member1   
left join
    Team team with member1.username = team.name */ select
        m1_0.member_id,
        m1_0.age,
        m1_0.team_id,
        m1_0.username,
        t1_0.team_id,
        t1_0.name 
    from
        member m1_0 
    left join
        team t1_0 
            on m1_0.username=t1_0.name

 

이거 보셈.

join 할 대상 지정은 했지만,

on에는 우리가 on으로 지정한 m.username = t.name만 들어있음.

 

'스프링데이터 + JPA > QueryDSL' 카테고리의 다른 글

17. 서브 쿼리  (0) 2023.11.30
16. join fetch  (0) 2023.11.29
14. join  (0) 2023.11.29
13. 그룹  (0) 2023.11.29
12. 페이징  (0) 2023.11.28