(JPA)JPQL 조인
JPQL 조인
조인 종류
내부 조인
SELETE m FROM Member m [INNER] JOIN m.team t
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setUsername("member");
member.setAge(10);
em.persist(member);
em.flush();
em.clear();
String query = "select m from Member m inner join m.team t";
List<Member> result = em.createQuery(query, Member.class)
.getResultList();
inner
는 생략이 가능하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Hibernate:
/* select
m
from
Member m
inner join
m.team t */
select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.team_id as team_id4_0_,
member0_.username as username3_0_
from
Member member0_
inner join
Team team1_
on member0_.team_id=team1_.id
- 발생한
Query
,inner join
이 잘 되는걸 확인할 수 있다.
외부 조인
SELETE m FROM Member m LEFT [OUTER] JOIN m.team t
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setUsername("member");
member.setAge(10);
em.persist(member);
em.flush();
em.clear();
String query = "select m from Member m left outer join m.team t";
List<Member> result = em.createQuery(query, Member.class)
.getResultList();
outer
는 생략이 가능하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Hibernate:
/* select
m
from
Member m
left outer join
m.team t */
select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.team_id as team_id4_0_,
member0_.username as username3_0_
from
Member member0_
left outer join
Team team1_
on member0_.team_id=team1_.id
- 발생한
Query
세타 조인
SELETE COUNT(m) FROM Member m, Team t WHERE m.username = t.name
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setUsername("member");
member.setAge(10);
em.persist(member);
em.flush();
em.clear();
String query = "select m from Member m, Team t where m.username = t.name";
List<Member> result = em.createQuery(query, Member.class)
.getResultList();
연관관계가 없는 데이터를 조인
카테시안 곱이 발생
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Hibernate:
/* select
m
from
Member m,
Team t
where
m.username = t.name */
select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.team_id as team_id4_0_,
member0_.username as username3_0_
from
Member member0_ cross
join
Team team1_
where
member0_.username=team1_.name
- 발생한
Query
,cross join
이 발생한다.
ON 절
- ON 절을 활용한 조인(JPA 2.1부터 지원)
조인 대상 필터링
- 회원과 팀을 조인하면서, 팀 이름이
A
인 팀만 조인- JPQL:
SELECTE 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'
- JPQL:
- 회원의 이름과 팀의 이름이 같은 대상 외부 조인(연관관계가 없는 엔티티 외부 조인)
- 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:
서브 쿼리
메인 쿼리와 연관이 없는 서브쿼리
- 나이가 평균보다 많은 회원
1 2
SELECT m FROM Member m WHERE m.age > (select avg(m2.age) from Member m2)
- 메인 쿼리와 서브 쿼리가 연관이 없어 따로 동작하므로 성능적인 측면에서 더 좋다.
메인 쿼리와 연관이 있는 서브쿼리
- 한 건이라도 주문한 고객
1 2
SELECT m FROM Member m WHERE (select count(o) from Order o where m = o.member) > 0
- 메인 쿼리와 서브 쿼리가 연관이 있는 상태
서브 쿼리 지원 함수
- [NOT] EXISTS (subquery): 서브 쿼리에 결과가 존재하면 참
- {ALL, ANY, SOME} (subquery)
- ALL: 모두 만족하면 참
- ANY, SOME: 같은 의미, 조건을 하나라도 만족하면 참
- [NOT] IN (subquery): 서브 쿼리의 결과 중 하나라도 같은 것이 있으면 참
지원 함수 예제
- 팀 A 소속인 회원
1 2
SELECT m FROM Member m WHERE EXISTS (select t from m.team t where t.name = '팀A')
- 전체 상품 각각의 재고보다 주문량이 많은 주문들
1 2
SELECT o FROM `Order` o WHERE o.orderAmount > ALL (select p.stockAmount from Product p)
- 어떤 팀이든 팀에 소속되 회원
1 2
SELECT m FROM Member m WHERE m.team = ANY (select t from Team t)
JPA 서브 쿼리의 한계
- JPA는
WHERE
,HAVING
절에서만 서브 쿼리를 사용할 수 있다. - Hibernate 에서는
SELECT
절도 지원 FROM
절의 서브 쿼리는 현재 JPQL 에서는 불가능하다.- 조인으로 풀 수 있으면 풀어서 해결 할 수 있다.
REFERENCE
#JPA_JPQL_조인
This post is licensed under CC BY 4.0 by the author.