JPA

Querydsl 서브쿼리

쭈녁 2024. 3. 31. 23:10

 

 

Querydsl에서 서브쿼리 사용 시 새로운 Q타입의 객체를 생성하여 중첩되지 않도록 사용하여야 한다.

 

1. Where 절에 서브쿼리 사용 예 1

/**
 * 나이가 가장 많은 회원
 */
@Test
public void subQuery() throws Exception {
    QMember sub = new QMember("memberSub");		// 서브쿼리 Q타입 객체 생성
    //when
    List<Member> result = queryFactory
            .selectFrom(member)
            .where(member.age.eq(
                    JPAExpressions
                            .select(sub.age.max())
                            .from(sub)))    //fetch는 하지 않는다
            .fetch();

    //then
    assertThat(result).extracting("age").containsExactly(40);
}

 

2. Where 절에 서브쿼리 사용 예 2

/**
 * 나이가 평균 이상 회원
 */
@Test
public void subQueryGoe() throws Exception {
    QMember sub = new QMember("memberSub");
    //when
    List<Member> result = queryFactory
            .selectFrom(member)
            .where(member.age.goe(
                    JPAExpressions
                            .select(sub.age.avg())
                            .from(sub)))    //fetch는 하지 않는다
            .fetch();

    //then
    assertThat(result).extracting("age").containsExactly(30, 40);
}

 

3. Where 절에 in을 사용하여 List타입으로 필터링

/**
 * 나이가 평균 이상 회원
 */
@Test
public void subQueryIn() throws Exception {
    QMember sub = new QMember("memberSub");
    //when
    List<Member> result = queryFactory
            .selectFrom(member)
            .where(member.age.in(
                    JPAExpressions
                            .select(sub.age)
                            .from(sub)
                            .where(sub.age.gt(10))))    //fetch는 하지 않는다
            .fetch();

    //then
    assertThat(result).extracting("age").containsExactly(20, 30, 40);
}

 

4. Select 절에 사용 예시

각기 다른 여러 타입을 조회 시 Querydsl은 Tuple이라는 객체에 여러 타입을 담아줌

@Test
public void selectSubQuery() throws Exception {
    QMember sub = new QMember("memberSub");
    //when

    List<Tuple> result = queryFactory
            .select(member.username,
                    JPAExpressions
                            .select(sub.age.avg())
                            .from(sub))
            .from(member)
            .fetch();
    for (Tuple tuple : result) {
        System.out.println("tuple = " + tuple);
    }
}

 

 

더보기

** !! JPA의 한계 : from 절 서브쿼리가 되지 않는다. 해결방안은 아래와 같다.!! **

1. from 절의 서브쿼리를 join으로 대체 (불가능한 상황이 간혹 있다)
2. 애플리케이션에서 쿼리를 2번으로 분리하여 실행
3. nativeSQL을 사용한다.

중요!! : 쿼리는 데이터를 퍼올리는 용도로만 사용하고 애플리케이션단에서 조합한다.
쓸데없는 서브쿼리의 남용을 피해야 하며 한방 쿼리가 필요한 시점이 언제인지 고민해야 한다.
(필요 시점) ->> 전체 조회와 같은 성능이 중요한 경우에 한방

참고자료

김영한 : 실전! Querydsl

https://www.inflearn.com/course/querydsl-%EC%8B%A4%EC%A0%84/dashboard

 

실전! Querydsl | 김영한 - 인프런

김영한 | Querydsl의 기초부터 실무 활용까지, 한번에 해결해보세요!, 복잡한 쿼리, 동적 쿼리는 이제 안녕! Querydsl로 자바 백엔드 기술을 단단하게. 🚩 본 강의는 로드맵 과정입니다. 본 강의는 자

www.inflearn.com