[JPA] JPQL - 서브쿼리
18 Aug 2022해당 포스트는 인프런 김영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 을 듣고 정리한 글입니다.
서브쿼리
JPA의 서브쿼리는 SQL 에서 말하는 서브쿼리와 동일하다. SELECT와 같은 쿼리안에 또다른 쿼리를 넣어 실행시키는 것을 말한다.
SELECT M.ID
,(SELECT T.NAME
FROM TEAM T
WHERE M.ID = T.MEMBER_ID) AS TEAM_NAME
FROM MEMBER M
위와 같이 MEMBER쿼리 안에 TEAM의 NAME을 조회하는 쿼리를 집어넣어 데이터를 조회하고 있다.
JPQL의 서브쿼리
- 나이가 평균보다 많은 회원
select m from Member m where m.age > (select avg(m2.age) from Member m2)
- 한 건이라도 주문한 고객
select m from Member m where (select count(o) from Order o where m = o.member) > 0
예시
간단하게 스칼라 서브쿼리를 jpql로 구현해보았다.
String subQuery = "select (select avg(m1.age) from Member m1) as avgAge from Member";
List<Object[]> result = entityManager.createQuery(subQuery)
.getResultList();
/* select
(select
avg(m1.age)
from
Member m1) as avgAge
from
Member */ select
(select
avg(cast(member1_.age as double))
from
Member member1_) as col_0_0_
from
Member member0_
서브 쿼리 지원 함수
- [NOT] EXISTS (subquery): 서브쿼리에 결과가 존재하면 참
- ALL, ANY, SOME (subquery)
- ALL : 모두 만족하면 참
- ANY, SOME: 같은 의미, 조건을 하나라도 만족하면 참
- ALL의 예시
팀A 소속인 회원 : select m from Member m where exists (select t from m.team t where t.name = ‘팀A’)
- ANY의 예시
전체 상품 각각의 재고보다 주문량이 많은 주문들 : select o from Order o where o.orderAmount > ALL (select p.stockAmount from Product p)
- SOME의 예시
어떤 팀이든 팀에 소속된 회원 : select m from Member m where m.team = ANY (select t from Team t)
- [NOT] IN (subquery): 서브쿼리의 결과 중 하나라도 같은 것이 있으면 참
한계
- JPA는 WHERE, HAVING 절에서만 서브 쿼리 사용 가능
- SELECT 절도 가능(하이버네이트에서 지원)
- FROM 절의 서브 쿼리는 현재 JPQL에서 불가능
- 조인으로 풀 수 있으면 풀어서 해결
- 차선책으로는 네이티브 쿼리 또는 쿼리를 N번 날리는 방법이 있다.
- 하지만 네이티브 쿼리와 같은 경우 View에서 원하는 데이터 타입을 맞추기가 어렵다.