개요
- 서브 쿼리를 작성해보자.
- 서브 쿼리는
com.querydsl.jpa.JPAExpressions 를 사용한다.
JPAExpressions는 static import 를 사용하는 것을 권장한다.
서브 쿼리
/**
* 나이가 가장 많은 회원 조회
*/
@Test
void subQuery() {
//given
QMember memberSub = new QMember("memberSub");
//when
List<Member> result = jpaQueryFactory
.selectFrom(member)
.where(member.age.eq(
JPAExpressions.select(memberSub.age.max())
.from(memberSub)
))
.fetch();
//then
assertThat(result)
.extracting("age")
.containsExactly(40);
}
/**
* 나이가 평균 이상인 회원
*/
@Test
void subQueryGoe() {
//given
QMember memberSub = new QMember("memberSub");
//when
List<Member> result = jpaQueryFactory
.selectFrom(member)
.where(member.age.goe(
JPAExpressions.select(memberSub.age.avg())
.from(memberSub)
))
.fetch();
//then
assertThat(result)
.extracting("age")
.containsExactly(30, 40);
}
/**
* 서브쿼리 여러 건 처리, in 사용
*/
@Test
void subQueryIn() {
//given
QMember memberSub = new QMember("memberSub");
//when
List<Member> result = jpaQueryFactory
.selectFrom(member)
.where(member.age.in(
JPAExpressions.select(memberSub.age)
.from(memberSub)
.where(memberSub.age.gt(10))
))
.fetch();
//then
assertThat(result)
.extracting("age")
.containsExactly(20, 30, 40);
}
/**
* select 절에 사용하는 서브쿼리 (스칼라 서브쿼리)
* 하이버네이트 구현체를 사용하면 select 절의 서브쿼리는 지원
*/
@Test
void selectSubQuery() {
//given
QMember memberSub = new QMember("memberSub");
//when
List<Tuple> result = jpaQueryFactory
.select(member.userName,
JPAExpressions
.select(memberSub.age.avg())
.from(memberSub))
.from(member)
.fetch();
//then
for (Tuple tuple : result) {
System.out.println("tuple = " + tuple);
}
// Console Log
// tuple = [member1, 25.0]
// tuple = [member2, 25.0]
// tuple = [member3, 25.0]
// tuple = [member4, 25.0]
}
- 외부 쿼리에 있는 member 와 내부 쿼리에 member 는 별칭(Alias)이 중복되면 안된다.
- QMember member = QMember.member;
- QMember memberSub = new QMember("memberSub");
- from 절의 서브쿼리 한계
- JPA JPQL 서브쿼리의 한계점으로 from 절의 서브쿼리(인라인 뷰)는 지원하지 않는다.
- 당연히 JPQL 의 빌더 역할을 하는 Querydsl 도 지원하지 않는다.
- from 절의 서브쿼리 해결방안
- 서브쿼리를 JOIN 으로 변경한다. (가능한 상황도 있고, 불가능한 상황도 있다)
- 애플리케이션에서 쿼리를 2번 분리해서 실행한다. (꼭 성능 확인)
- nativeSQL 을 사용한다.