몬그로이

SubQuery, JPAExpressions 본문

Organizing Docs/Java Docs

SubQuery, JPAExpressions

Mon Groy 2024. 7. 1. 20:00

사용하는 때

1. 복잡한 조건을 사용해야 할 때

메인 쿼리에서 사용하기 어려운 복잡한 조건을 처리하기 위해
예) 특정 조건에 맞는 데이터만 필터링해야 할 때

 

2. 집계 함수와 함께 사용할 때

집계된 데이터를 메인 쿼리에서 다시 처리하기 위해

예) 특정 그룹의 최대값, 최소값, 평균값 등을 구하고 이를 메인 쿼리에서 사용

 

3. 존재 유무 확인

특정 조건에 맞는 데이터가 존재하는지 확인할 때

예) 특정 조건을 만족하는 레코드가 존재하는 경우에만 데이터를 조회할 때

 

4. 순위 및 순번 지정

특정 순위나 순번을 지정하기 위해

예) 각 그룹 내에서 순위를 매기거나, 순번을 지정할 때


예시

 

1. 복잡한 조건을 처리하기 위한 서브쿼리

가장 최근 주문 날짜를 가진 고객을 조회하는 경우

SELECT * FROM Customer c

WHERE c.order_date = (SELECT MAX(order_date) FROM Orders o WHERE o.customer_id = c.id);

 

2. 집계 함수와 함께 사용

각 부서의 평균 급여보다 높은 급여를 받는 직원 조회

SELECT * FROM Employee e

WHERE e.salary > (SELECT AVG(salary) FROM Employee WHERE department_id = e.department_id);

 

3. 존재 유무 확인

주문이 있는 고객 조회

SELECT * FROM Customer c

WHERE EXISTS (SELECT 1 FROM Orders o WHERE o.customer_id = c.id);

 

4. 순위 및 순번 지정

각 부서에서 급여 순위가 높은 직원 조회

SELECT * FROM Employee e1

WHERE salary > (

SELECT AVG(salary)

FROM Employee e2

WHERE e1.department_id = e2.department_id

);

 


QueryDSL에서의 서브쿼리 사용 예시

 

1. 복잡한 조건을 처리하기 위한 서브쿼리 - 가장 큰 나이를 가진 멤버 찾기

QMember memberSub = new QMember("memberSub");

 

List<Member> result = queryFactory

      .selectFrom(member)

       .where(member.age.eq(

              JPAExpressions

                     .select(memberSub.age.max())

                     .from(memberSub)

       ))

       .fetch();

 

2. 집계 함수와 함께 사용

QMember memberSub = new QMember("memberSub");

 

List<Member> result = queryFactory

       .selectFrom(member)

       .where(member.salary.gt(

              JPAExpressions

                     .select(memberSub.salary.avg())

                     .from(memberSub)

                     .where(memberSub.department.id.eq(member.department.id))

       ))

       .fetch();

 

3. 존재 유무 확인

QOrder order = QOrder.order;

 

List<Customer> result = queryFactory

       .selectFrom(customer)

       .where(

              JPAExpressions

                     .selectOne()

                     .from(order)

                     .where(order.customer.id.eq(customer.id))

                     .exists()

)

.fetch();

 

4. 순위 및 순번 지정

QMember memberSub = new QMember("memberSub");

 

List<Member> result = queryFactory

       .selectFrom(member)

       .where(member.salary.gt(

              JPAExpressions

                     .select(memberSub.salary.avg())

                     .from(memberSub)

                     .where(memberSub.department.id.eq(member.department.id))

))

.fetch();

 


JPAExpressions: 서브쿼리를 작성하는 데 사용되는 도구

 

서브 쿼리 주요 메서드

 

  • select: 서브쿼리를 시작하는 데 사용됩니다.
  • selectOne: SELECT 1과 같이 단일 상수를 반환하는 서브쿼리를 작성합니다.
  • selectFrom: 특정 테이블 또는 엔티티를 대상으로 서브쿼리를 작성합니다.
  • exists: 존재 여부를 확인하는 서브쿼리를 작성합니다.
  • notExists: 존재하지 않음을 확인하는 서브쿼리를 작성합니다.

 

 

JPA JPQL 서브쿼리의 한계

from 절에서 사용 불가

- Hibernate 구현체를 사용하면 Hibernate 에서 지원해주기 때문에 select 절에서 사용이 가능한 것

 

해결 방안

  • 서브쿼리를 join 으로 변경(불가능할 때도 있으나 가능한 경우가 많음)
  • 애플리케이션에서 쿼리를 2번 분리해서 실행한다
  • 정 안 될때는 nativeSQL 사용할 것

 

 

'Organizing Docs > Java Docs' 카테고리의 다른 글

자바의 정석 8. 예외처리  (1) 2024.07.05
Coding 01  (0) 2024.07.04
JPQL - 복잡한 쿼리를 수동으로 작성하고 실행하는 방법  (0) 2024.06.30
ORM  (0) 2024.06.28
Spring Data JPA  (0) 2024.06.28