ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Querydsl - 서브 쿼리
    JPA/Querydsl 2023. 8. 13. 00:18

    서브 쿼리는 com.querydsl.jpa.JPAExpressions을 사용한다.

    /**
    * 나이가 가장 많은 회원 조회
    */
    @Test
    public void subQuery() {
           
        QMember memberSub = new QMember("memberSub");
    
        List<Member> result = queryFactory
                .selectFrom(member)
                .where(member.age.eq(
                        JPAExpressions
                                .select(memberSub.age.max())
                                .from(memberSub)
                ))
                .fetch();
            
        assertThat(result).extracting("age")
                .containsExactly(40);
    }

     

    .where(member.age.eq(JPAExpressions.select(memberSub.age.max()).from(memberSub)))

    서브 쿼리인 값이 40이 될 것이고 where문의 조건은 나이가 40인 사람이 될 것이다.

     

     

     

    평균 이상을 조회

    /**
    * 나이가 평균 나이 이상인 회원
    */
    @Test
    public void subQueryGoe() throws Exception {
            
        QMember memberSub = new QMember("memberSub");
            
        List<Member> result = queryFactory
                .selectFrom(member)
                .where(member.age.goe( // goe의 뜻은 평균보다 큰 것을 찾는다는 뜻
                        JPAExpressions
                                .select(memberSub.age.avg())
                                .from(memberSub)
                ))
                .fetch();
                
        assertThat(result).extracting("age")
                .containsExactly(30, 40);
    }

    평균보다 나이가 많은 사람을 조회하는 서브 쿼리이다. JPAExpression을 통해 나이 평균을 select했고, goe()를 통해 평균보다 나이가 많은 사람을 최종적으로 select한다.

     

     

     

    in 절을 사용

    /**
    * 서브쿼리 여러 건 처리, in 사용
    */
    @Test
    public void subQueryIn() throws Exception {
        QMember memberSub = new QMember("memberSub");
            
        List<Member> result = queryFactory
                .selectFrom(member)
                .where(member.age.in(
                        JPAExpressions
                                .select(memberSub.age)
                                .from(memberSub)
                                .where(memberSub.age.gt(10))
                ))
                .fetch();
    
        assertThat(result).extracting("age")
                .containsExactly(20, 30, 40);
    }

    in 절을 사용할 때에도 서브 쿼리는 똑같이 들어간다.

     

     

     

    select 절에 서브 쿼리 사용

    @Test
    public void selectSubQuery() {
        QMember memberSub = new QMember("memberSub");
    
        List<Tuple> fetch = queryFactory
                .select(member.username,
                        // JPAExpressions -> static import
                                .select(memberSub.age.avg())
                                .from(memberSub)
                ).from(member)
               .fetch();
    
        for (Tuple tuple : fetch) {
            System.out.println("username = " + tuple.get(member.username));
            System.out.println("age = " +
                    tuple.get(JPAExpressions.select(memberSub.age.avg())
                            .from(memberSub)));
        }
    }

    select 절에 서브 쿼리를 사용하는 것도 크게 다르지 않다.

     

    참고로 JPAExpressions는 static import로 생략을 해줄 수 있다.

     

     

     

    JPA의 서브쿼리는 from 절에서 서브쿼리를 사용할 수 없다. Querydsl에서도 지원하지 않지만 하이버네이트 구현체를 사용하면 select 절에서는 서브쿼리를 사용할 수 있다.

     

     

     

    from 절의 서브쿼리를 하려면?

    1. 서브쿼리를 join으로 변경한다. (불가능할 때도 있음)

    2. 애플리케이션에서 쿼리를 2번 분리해서 실행한다.

    3. nativeSQL을 사용한다.

    'JPA > Querydsl' 카테고리의 다른 글

    Dto로 프로젝션 결과 반환  (0) 2023.08.13
    Querydsl - Case 문  (0) 2023.08.13
    Querydsl - 조인  (0) 2023.08.13
    Querydsl - 정렬과 페이징, 집합  (0) 2023.08.12
    Querydsl - 검색(select)과 결과 조회  (0) 2023.08.12
Designed by Tistory.