[Querydsl]기본 문법(3) - 서브 쿼리

2024. 8. 9. 18:25· 인프런 김영한 강의 정리/실전! Querydsl
목차
  1. 1. JPAExpressions
  2. 2. Q클래스 인스턴스
  3. 3. 서브쿼리 사용 
  4. 1) SELECT 절에 서브쿼리 사용
  5. 2) WHERE 절에 서브쿼리 사용
  6. 4. FROM 절의 서브쿼리 해결방안
  7. 1) 서브쿼리를 join으로 변경한다. (가능한 상황도 있고, 불가능한 상황도 있다.)
  8. 2) 애플리케이션에서 쿼리를 2번 분리해서 실행한다.
728x90

1. JPAExpressions

Querydsl에서 서브쿼리를 작성할 때, com.querydsl.jpa.JPAExpressions 사용해야한다.

List<Member> result = queryFactory
    .selectFrom(member)
    .where(member.age.eq(
        JPAExpressions
            .select(memberSub.age.max())
            .from(memberSub)
    ))
    .fetch();

서브쿼리 시작할 때 JPAExpressions를 붙이면 된다.

 

static import해서 쓰자!

import static com.querydsl.jpa.JPAExpressions.select;

static import하고 나면 JPAExpressions를 따로 붙일 필요없이 select로 시작하면 된다.

 

참고로, 인텔리제이에서 Alt + Enter를 눌러도 static import 추가 버튼이 안뜬다면 설정에 들어가서 Add on-demand static import를 체크해주면 된다.

 

2. Q클래스 인스턴스

메인 쿼리와 서브쿼리의 조회대상 엔티티가 같다면, Q클래스 인스턴스를 생성해서 별칭을 직접 지정해줘야한다.

public void subQuery(){
        QMember memberSub = new QMember("memberSub");

        List<Member> result = queryFactory
                .selectFrom(member)
                .where(member.age.eq(
                        		select(memberSub.age.max())
                                .from(memberSub)
                ))
                .fetch();
    }

이 예제에서는 메인쿼리에와 서브쿼리가 모두 member를 조회하기 때문에 memberSub로 별칭을 직접 지정해줬다.

 

 

3. 서브쿼리 사용 

1) SELECT 절에 서브쿼리 사용

요구사항 : 각 회원의 ID, 이름과 함께 해당 회원이 가장 최근 작성한 게시물 제목을 조회하라.

//member, post, JPAExpressions는 static import

List<Tuple> result = queryFactory
    .select(
        member.id,
        member.name,
           select(post.title)
          .from(post)
          .where(post.member.id.eq(member.id))
          .orderBy(post.createdAt.desc())
          .limit(1)
    )
    .from(member)
    .fetch();

다른 테이블의 특정 데이터를 함께 조회해야할 때 SELECT절에 서브쿼리를 사용하는 것이 유용하다.

 

2) WHERE 절에 서브쿼리 사용

요구사항 : 가장 높은 주문 금액이 1000 이상인 회원을 조회하라.

//member, orders, JPAExpressions는 static import했다고 가정

List<Member> result = queryFactory
    .selectFrom(member)
    .where(
          select(orders.amount.max())
          .from(orders)
          .where(orders.member.id.eq(member.id))
          .gt(1000)
    )
    .fetch();

집계 함수 결과에 따라 필터링 해야 하는 경우, 서브쿼리를 사용할 수 있다.

 

4. FROM 절의 서브쿼리 해결방안

Querydsl은 FROM절의 서브쿼리를 지원하지 않는다.

 

1) 서브쿼리를 join으로 변경한다. (가능한 상황도 있고, 불가능한 상황도 있다.)

요구사항: Orders 테이블에 amount가 100이상인 주문을 한 회원을 조회하라.

 

✅FROM절 서브쿼리(SQL)

SELECT m.*
FROM Member m
JOIN (
    SELECT o.member_id
    FROM Orders o
    WHERE o.amount >= 100
) sub ON m.id = sub.member_id;

 

✅조인으로 변경

List<Member> result = queryFactory
    .selectFrom(member)
    .join(member.orders, orders) 
    .where(orders.amount.goe(100))
    .fetch();

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

요구사항: 회원의 총 주문 금액이 1000이상인 회원의 정보를 조회 하라.

 

✅FROM절 서브쿼리(SQL)

SELECT m.*
FROM Member m
JOIN (
    SELECT o.member_id, SUM(o.amount) as total_amount
    FROM Orders o
    GROUP BY o.member_id
    HAVING SUM(o.amount) >= 1000
)sub ON m.id = sub.member_id;

이 쿼리는 조인으로 해결할 수 있지만 예시로 쿼리를 분리해본다.

 

✅쿼리 분리

List<Long> memberIds = queryFactory
    .select(orders.memberId)
    .from(orders)
    .groupBy(orders.memberId)
    .having(orders.amount.sum().goe(1000))
    .fetch();
    
List<Member> members = queryFactory
    .selectFrom(member)
    .where(member.id.in(memberIds))
    .fetch();

첫번째 쿼리로 조건에 맞는 회원ID를 조회하고 두번째 쿼리로 회원ID와 일치하는 회원 정보를 조회한다.

 

💡조인이나 쿼리를 분리하는 것만으로 해결이 안되는 FROM절은 nativeSQL로 해결해야한다.

nativeSQL을 쓰기전에 데이터만 간단하게 가져오고 애플리케이션에서 로직처리를 할 수 있는지 확인하자. 

복잡한 SQL대신 로직으로 해결할 수 있는 경우도 있다.

 

 

 

728x90

'인프런 김영한 강의 정리 > 실전! Querydsl' 카테고리의 다른 글

[Querydsl] 기본 문법(4) - Case문  (0) 2024.08.09
[Querydsl] 기본 문법(2) - 조인  (0) 2024.08.08
[Querydsl] fetchResults(), fetchCount() 대체하기  (0) 2024.08.07
[Querydsl] 기본 문법(1) - JPQL과 차이, 조회  (0) 2024.08.06
프로젝트 환경설정 (SpringBoot 3.x 버전), Querydsl 설정  (0) 2024.07.27
  1. 1. JPAExpressions
  2. 2. Q클래스 인스턴스
  3. 3. 서브쿼리 사용 
  4. 1) SELECT 절에 서브쿼리 사용
  5. 2) WHERE 절에 서브쿼리 사용
  6. 4. FROM 절의 서브쿼리 해결방안
  7. 1) 서브쿼리를 join으로 변경한다. (가능한 상황도 있고, 불가능한 상황도 있다.)
  8. 2) 애플리케이션에서 쿼리를 2번 분리해서 실행한다.
'인프런 김영한 강의 정리/실전! Querydsl' 카테고리의 다른 글
  • [Querydsl] 기본 문법(4) - Case문
  • [Querydsl] 기본 문법(2) - 조인
  • [Querydsl] fetchResults(), fetchCount() 대체하기
  • [Querydsl] 기본 문법(1) - JPQL과 차이, 조회
백엔드 개발자 - 젤리곰
백엔드 개발자 - 젤리곰
오늘도 배움이 있는 하루가 되길 바라는 개발자
백엔드 개발자 - 젤리곰
backend-gummyBear
백엔드 개발자 - 젤리곰
전체
오늘
어제
  • 분류 전체보기 (145) N
    • 인프런 김영한 강의 정리 (60)
      • 스프링 핵심원리 기본편 (12)
      • 모든 개발자를 위한 HTTP 웹 기본 지식 (10)
      • 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 (3)
      • 자바 ORM 표준 JPA 프로그래밍 기본편 (28)
      • 실전! Querydsl (6)
    • Spring (2)
    • 프로젝트일지 (6)
    • 프로그래밍 언어 (20)
      • Java (17)
      • JavaScript (3)
      • Python (0)
    • 데이터베이스 (4)
      • Oracle (2)
      • ORM (1)
      • SQL 튜닝 (1)
    • 형상관리 (1)
      • Git (0)
    • 알고리즘&자료구조 (34)
      • Algorithm (31)
      • Data Structure (1)
    • CS지식 (4)
    • Cloud (5)
    • 일기 (8) N
      • 공부 일기 (3)
      • 독서 일기 (2)
      • 마음 일기 (3) N

블로그 메뉴

  • 홈
  • 태그

공지사항

인기 글

태그

  • ORM프레임워크
  • 프론트엔드개발자업무
  • 스프링컨텍스트
  • 객체지향의사실과오해
  • 커스텀annotation
  • SublimeText단축키
  • 프론트엔드역사
  • LeetCode200번
  • 인프콘
  • jquery와javascript
  • 인터페이스
  • LeetCode17번
  • #{}와${}의차이
  • 업캐스팅
  • 객체지향방법론
  • 힙자료구조
  • dfs알고리즘
  • 데이터베이스정규화
  • 클라이언트서버통신
  • 다운캐스팅

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.2
백엔드 개발자 - 젤리곰
[Querydsl]기본 문법(3) - 서브 쿼리
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.