@Test
void subQuery() {
factory = new JPAQueryFactory(em);
QMember member = QMember.member;
QMember subMember = new QMember("sub"); // 서브쿼리 안에 있는 Member는 Alias 를 다르게 해줘야 하기 때문에 new QMember(name) 으로 Alias를 설정해서 생성
List<Member> result = factory
.selectFrom(member)
.where(member.age.eq(
JPAExpressions
.select(subMember.age.max())
.from(subMember)
))
.fetch();
//eq 외 gt, goe 등등 모두 사용 가능
Assertions.assertThat(result).extracting("age")
.containsExactly(55);
}
SELECT *FROM member WHERE age = (SELECT max(sub.age) FROM member sub);
@Test
void subQueryIn() {
factory = new JPAQueryFactory(em);
QMember member = QMember.member;
QMember subMember = new QMember("sub"); // 서브쿼리 안에 있는 Member는 Alias 를 다르게 해줘야 하기 때문에 new QMember(name) 으로 Alias를 설정해서 생성
List<Member> result = factory
.selectFrom(member)
.where(member.age.in(
JPAExpressions
.select(subMember.age)
.from(subMember)
.where(subMember.age.gt(40))
))
.fetch();
Assertions.assertThat(result).extracting("age")
.containsExactly(45, 55);
}
SELECT * FROM member WHERE age IN (SELECT sub.age FROM member sub WHERE sub.age > 40);
@Test
void subQuerySelect() {
factory = new JPAQueryFactory(em);
QMember member = QMember.member;
QMember subMember = new QMember("sub"); // 서브쿼리 안에 있는 Member는 Alias 를 다르게 해줘야 하기 때문에 new QMember(name) 으로 Alias를 설정해서 생성
List<Tuple> result = factory.select(member.username,
JPAExpressions
.select(subMember.age.avg())
.from(subMember))
.from(member)
.fetch();
for (Tuple tuple : result) {
System.out.println("tuple = " + tuple);
}
Assertions.assertThat(result.get(0).get(1, Double.class)).isEqualTo(40);
}
SELECT member.username, (SELECT avg(sub.age) FROM member sub) FROM member;
주의할 점:
1. 서브쿼리를 사용할때는 각각 다른 Alias로 해줘야 하는데, QueryDSL에서는 Q 엔티티를 생성할때 Alias를 지정해 줄 수 있습니다. 예를 들어, Member에 대해서 서브쿼리를 실행할 경우에는, new QMember("A")으로 SQL에서 'Member as A'/'Member A'와 같은 효과를 줄 수 있습니다.
2. JPA JPQL에서 기본적으로 from에서의 서브쿼리는 지원하지 않습니다. 그렇기 때문에 QueryDSL에서도 from에서 서브쿼리를 실행 할 수 없습니다.