JPA

[JPA] 23. JPQL - 조인, 서브 쿼리

inuma 2021. 1. 31. 22:10
프로젝트 git url github.com/rtef23/JpaStudy
필요 1. docker
2. docker-compose
프로젝트 정보 mysql : 5.7 - docker image
java : 1.8

 

조인

내부 조인

  • Inner Join
  • [JPQL] SELECT m FROM Member m [INNER] JOIN m.team t
@Entity
public class Member {
  @Id @GeneratedValue private Long id;

  private String username;

  private int age;

  //JPQL로 실행하더라도 엔티티 클래스의 Fetch 타입에 따라서 Team을 조인하는 시점이 달라진다.
  //xxxToOne 어노테이션의 기본 fetch는 EAGER이다.
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "team_id")
  private Team team;
  
  ...
}
List<Member> findMembers = entityManager.createQuery("select m from Member m inner join m.team t", Member.class).getResultList();

System.out.println(findMembers);
System.out.println("#### before getTeam()");
System.out.println(findMembers.get(0).getTeam());

 

외부 조인

  • Outer Join
  • [JPQL] SELECT m FROM Member m LEFT [OUTER] JOIN m.team t

 

세타 조인

  • 연관관계가 없는 테이블간의 조인(카테시안 곱)
  • [JPQL] SELECT COUNT(m) FROM Member m, Team t WHERE m.username = t.name
List<Member> result =
          entityManager.createQuery("select m from Member m ,Team t", Member.class).getResultList();

System.out.println(result);

/* team row 수 * member row 수의 결과 집합이 생성된다.(카테시안 곱)*/

 

ON절 활용

  • 조인 대상 필터링
//회원과 팀을 조인하면서, 팀 이름이 A인 팀만 조인
//[JPQL]
SELECT m, t 
  FROM Member m 
  LEFT JOIN m.team t
    ON t.name = 'A'

//[SQL]
SELECT m.*, t.*
  FROM Member m
  LEFT JOIN Team t
    ON m.team_id = t.id
   AND t.name = 'A'

 

  • 연관관계 없는 엔티티 외부 조인 (hibernate 5.1 이후 버전부터 사용 가능)
//회원 이름과 팀의 이름이 같은 대상 외부 조인
//[JPQL]
SELECT m, t
  FROM Member m
  LEFT JOIN Team t
    ON m.username = t.name

//[SQL]
SELECT m.*, t.*
  FROM Member m
  LEFT JOIN Team t
    ON m.username = t.name

 

서브쿼리

 

  • 나이가 평균보다 많은 회원
//[JPQL]
SELECT m
  FROM Member m
 WHERE m.age > (SELECT AVG(m2.age)
                  FROM Member m2)

 

  • 한 건이라도 주문한 고객
//[JPQL]
SELECT m
  FROM Member m
 WHERE (SELECT COUNT(o)
          FROM Order o
         WHERE m = o.member) > 0

 

지원 함수

  • [NOT] EXISTS : 서브쿼리에 결과가 존재하면 참
//[JPQL]
SELECT m
  FROM Member m
 WHERE EXISTS (SELECT t
                 FROM m.team t
                WHERE t.name = 'teamA')

 

  • ALL : 모두 만족하면 참
//[JPQL]
SELECT o
  FROM Order o
 WHERE o.orderAmount > ALL (SELECT p.stockAmount
                              FROM Product p)

 

  • ANY, SOME : 조건을 하나라도 만족하면 참
//[JPQL]
SELECT m
  FROM Member m
 WHERE m.team = ANY (SELECT t
                       FROM Team t)
                       
SELECT m
  FROM Member m
 WHERE m.team = SOME (SELECT t
                        FROM Team t)

 

  • [NOT] IN : 서브 쿼리의 경과중 하나라도 같은 것이 있으면 참

 

JPQ 서브쿼리 한계

  • JPA는 WHERE, HAVING 절에서만 서브 쿼리 사용 가능
  • Hibernate의 경우, SELECT 절(스칼라 서브 쿼리)에서도 가능
  • FROM 절의 서브 쿼리(인라인 뷰)는 현재 JPQL에서 불가능

 

'JPA' 카테고리의 다른 글

[JPA] 25. 경로표현식  (0) 2021.02.11
[JPA] 24. JPQL - 타입 표현, 기타식  (0) 2021.01.31
[JPA] 22. JPQL - 기본 문법 2  (0) 2021.01.27
[JPA] 21. JPQL - 기본 문법 1  (0) 2021.01.26
[JPA] 20. JPA 쿼리 방법 소개  (0) 2021.01.25