- 참조: 자바 ORM 표준 JPA 프로그래밍
- JPQL: https://docs.oracle.com/html/E13946_04/ejb3_langref.html
- 서브 쿼리
JPQL 도 SQL 처럼 서브 쿼리를 지원한다. 다만 SQL 처럼 SELECT, FROM, WHERE, HAVING 절에 쓸 수 있는것은 아니고 WHERE 와 HAVING 절에서만 쓸 수 있다.
하이버네이트 HQL 은 SELECT 절의 서브쿼리를 허용하며 일부 JPA 구현체는 FROM 절의 서브쿼리도 지원하므로 자신이 사용할 구현체의 스펙을 잘 알아보고 사용하도록 하자.
SQL 의 기본적인 문법은 다루지 않는다. JPQL 의 특성을 이용한 문법을 사용해보자.
Member member = new Member();
member.setName("User#1");
Address address1 = new Address("City#1", "Street#1", "Zipcode#1");
member.setAddress(address1);
em.persist(member);
Member member2 = new Member();
member2.setName("User#2");
Address address2 = new Address("City#2", "Street#2", "Zipcode#2");
member2.setAddress(address2);
em.persist(member2);
Order order1 = new Order();
order1.setMember(member);
order1.setStatus(OrderStatus.ORDER);
Delivery delivery1 = new Delivery();
delivery1.setAddress(address1);
order1.setDelivery(delivery1);
em.persist(order1);
Order order2 = new Order();
order2.setMember(member);
order2.setStatus(OrderStatus.ORDER);
Delivery delivery2 = new Delivery();
delivery2.setAddress(address1);
order2.setDelivery(delivery2);
em.persist(order2);
위의 코드는 User#1 회원은 2 건의 주문을 User#2 회원은 주문을 하지 않은 상황을 표현한 코드이다. 이런 상황에서 주문을 1 건 이상한 회원을 조회하는 JPQL 을 작성해보자.
String jpql = "select m "
+ "from Member m "
+ "where (select count(o) from m.orders o where o.member = m) > 0";
List<Member> members = em.createQuery(jpql, Member.class)
.getResultList();
members.forEach(member -> {
System.out.println("Member name: " + member.getName());
});
우리가 아는 SQL 와 비슷하게 작성되었다. SQL 로 작성한다면 o.member = m 과 같이 엔티티 비교가 아니라 회원의 ID 키를 이용하였을 것이다. 또한 count 도 count(1) 과 같이 값이 아닌 엔티티의 alias o 에 대해 count(o) 로 표현하였다.
m.orders 가 컬렉션임을 이용하면 더 간단하게도 작성할 수 있다.
tring jpql = "select m "
+ "from Member m "
+ "where m.orders.size > 0";
List<Member> members = em.createQuery(jpql, Member.class)
.getResultList();
members.forEach(member -> {
System.out.println("Member name: " + member.getName());
});
복잡한 서브쿼리 대신 m.orders.size 를 이용하여 주문건이 있는 회원조건을 표현하였다.
Hibernate:
/* select
m
from
Member m
where
(
select
count(o)
from
m.orders o
where
o.member = m
) > 0 */ select
member0_.member_id as member_i1_4_,
member0_.insert_datetime as insert_d2_4_,
member0_.update_datetime as update_d3_4_,
member0_.city as city4_4_,
member0_.street as street5_4_,
member0_.zipcode as zipcode6_4_,
member0_.name as name7_4_
from
member member0_
where
(
select
count(orders1_.order_id)
from
orders orders1_
where
member0_.member_id=orders1_.member_id
and orders1_.member_id=member0_.member_id
)>0
Member name: User#1
...................................................
Hibernate:
/* select
m
from
Member m
where
m.orders.size > 0 */ select
member0_.member_id as member_i1_4_,
member0_.insert_datetime as insert_d2_4_,
member0_.update_datetime as update_d3_4_,
member0_.city as city4_4_,
member0_.street as street5_4_,
member0_.zipcode as zipcode6_4_,
member0_.name as name7_4_
from
member member0_
where
(
select
count(orders1_.member_id)
from
orders orders1_
where
member0_.member_id=orders1_.member_id
)>0
Member name: User#1
위의 2 예제를 수행해보면 SQL 문법이 다르긴 하지만 유의미한 차이가 있을만큼 아주 큰 차이는 없다.
- 서브 쿼리 함수
JPQL 의 서브 쿼리는 [NOT] EXISTS, {ALL | ANY | SOME}, [NOT] IN 와 같은 연산자를 사용할 수 있다. 서브 쿼리에서 사용하는 함수들은 SQL 에서 사용하는 함수들과 큰 차이는 없다. EXISTS 에 대한 예제만 간단하게 살펴보자.
String jpql = "select m "
+ "from Member m "
+ "where exists (select o "
+ " from m.orders o "
+ " where o.delivery.address.city = 'City#1')";
List<Member> members = em.createQuery(jpql, Member.class)
.getResultList();
members.forEach(member -> {
System.out.println("Member name: " + member.getName());
});
언급한 서브쿼리 함수들은 설명보다는 필요할 때 마다 써보면서 익히면 된다.
- 조건식
JPQL 도 SQL 처럼 많은 조건식을 지원한다. JPQL 에서 사용하는 특이한 조건식만 살펴보고 넘어가보도록 하자.
- Enum: 패키지명을 포함한 전체 이름을 사용해야 한다. ex) jpabook.MemberType.Admin
- 엔티티 타입: 엔티티의 타입을 표현할 수 있다. ex) TYPE(m) = Member
- 컬렉션 식: 컬렉션 식에서만 사용하는 기능 ex) m.orders is not empty
이 외에도 CASE WHEN, 문자열 함수, 논리 연산 등 많은 연산을 지원한다. JPQL 을 자세히 알고 싶은 사람은 https://docs.oracle.com/html/E13946_04/ejb3_langref.html 를 참조하자.
'Framework and Tool > JPA' 카테고리의 다른 글
JPA - 객체지향 쿼리 언어 - JPQL NamedQuery (0) | 2021.08.03 |
---|---|
JPA - 객체지향 쿼리 언어 - JPQL 다형성 쿼리 (0) | 2021.08.03 |
JPA - 객체지향 쿼리 언어 - JPQL 경로 표현식 (0) | 2021.08.02 |
JPA - 객체지향 쿼리 언어 - JPQL Fetch Join (0) | 2021.07.31 |
JPA - 객체지향 쿼리 언어 - JPQL Join (0) | 2021.07.31 |
댓글