😄
JPA 기본 강의 정리 - 10. JPQL 정리_02
January 17, 2022
JPQL
- 프로젝션
- 페이징
- 조인
- 서브 쿼리
- JPQL 타입 표현
- 조건식
- 기본 함수와 사용자 정의 함수
1. 프로젝션
- SELECT 절에 조회할 대상을 지정하는 것.
1) 대상
타입 | 예시 |
---|---|
엔티티 프로젝션 | SELECT m FROM Member m |
SELECT m.team FROM Member m | |
임베디드 타입 프로젝션 | SELECT m.address FROM Member m |
스칼라 타입 프로젝션 (기본 데이터 타입) | SELECT m.username, m.age FROM Member m |
2) 여러 타입 값 조회
- Query 타입
Query query = em.createQuery("SELECT m.username, m.age from Member m");
List resultList = query.getResultList();
Object o = resultList.get(0);
Object[] result = (Object[]) o;
System.out.println("result = " + result[0]);
System.out.println("result = " + result[1]);
- Query는 Object를 반환하기에 타입 캐스팅이 필요하다.
- Object[] 타입
List<Object[]> resultList = em.createQuery("SELECT m.username, m.age from Member m").getResultList();
Object[] result = resultList.get(0);
System.out.println("result = " + result[0]);
System.out.println("result = " + result[1]);
- 위의 Query 타입을 앞서 타입캐스팅하는 것과 동일한 이치로 보면 된다.
- new 명령어 조회
// MemberDTO.java
public class MemberDTO {
private String username;
private int age;
public MemberDTO(String username, int age) {
this.username = username;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
List<MemberDTO> result = em.createQuery("SELECT new jpql.MemberDTO(m.username,m.age) from Member m", MemberDTO.class).getResultList();
MemberDTO memberDTO = result.get(0);
System.out.println("memberDTO.username = " + memberDTO.getUsername());
System.out.println("memberDTO.age = " + memberDTO.getAge());
- 위와 같이 DTO로 조회 결과를 SQL문에서 매핑하는 것이 가능하다.
- new 생성자로 매핑 시, 패키지 명을 모두 써야하는 것이 눈여겨 봐야하는 점이다. 이 과정은 꽤 불편하기에 단축하는 과정이 있다. ( 추후 학습 )
2. 페이징 API
- 2가지 API로 추상화.
- setFirstResult(int startPosition) : 조회 시작 위치
- setMaxResults(int maxResult) : 조회할 데이터 수
3. 조인
- 동작 방식은 DB와 동일하다.
DB | JPA |
---|---|
Inner Join | 내부 조인 |
Outer Join | 외부 조인 |
세타 조인 (속칭: 막조인) |
- 세타 조인 예시
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setUsername("teamA");
member.setAge(10);
member.setTeam(team);
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();
System.out.println("result = " + result.size());
-
위에서 유심히 봐야할 것은 쿼리문이다.
-
실행결과
* JPA 조인 특징
-
조인 대상 필터링
-
ex) 회원과 팀을 조인하면서, 팀 이름이 A인 팀만 조인 가능. ( 아래 두 쿼리 확인 )
# SQL SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.TEAM_ID=t.id and t.name='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.username = t.name
// java SELECT m, t FROM Member m LEFT JOIN Team t on m.username = t.name
-
4. 서브 쿼리
- 일반적인 SQL에서의 서브 쿼리와 동일.
1) 서브 쿼리 지원 함수
함수 | 설명 |
---|---|
1. [ NOT ] EXISTS (subquery) | 서브 쿼리에 결과가 존재하면 참 |
2. { ALL | ANY | SOME } (subquery) | 1. ALL - 모두 만족하면 참 2. ANY, SOME - 같은 의미, 조건을 하나라도 만족하면 참 |
3. [ NOT ] IN (subquery) | 서브 쿼리의 결과 중 하나라도 같은 것이 있으면 참 |
2) 지원 함수 예제
-
[ NOT ] EXISTS (subquery)
- 팀 A 소속인 회원
select m from Member m where exists (select t from m.team t where t.name = '팀A')
-
{ ALL | ANY | SOME } (subquery)
- 전체 상품 각각의 재고보다 주문량이 많은 주문들
select o from Order o where o.orderAmount > ALL (select p.stockAmount from Product p)
- 어떤 팀이든 팀에 소속된 회원
select m from Member m where m.team = ANY (select t from Team t)
3) JPA 서브 쿼리 한계
- WHERE, HAVING 절에만 서브 쿼리 사용 가능
- FROM 절의 서브 쿼리는 JPQL에서 불가능 → 조인으로 풀 수 있으면 풀어서 해결!
5. JPQL 타입 표현
-
문자: ‘JPA’
-
숫자: 10L (Long), 10D (Double), 10F (Float)
-
Boolean: TRUE, FALSE
-
ENUM
- SQL 쿼리에 하드코딩 하는 경우
- 사용하려는 ENUM 타입의 패키지명 포함 + 변수 (ex - jpabook.MemberType.Admin)
- 변수 파라미터로 바인딩 하는 경우
- 일반적인 타입으로 바인딩하는 것과 동일.
- SQL 쿼리에 하드코딩 하는 경우
-
엔티티 타입: TYPE(m) = Member (상속 관계에서 사용)
select i from Item i where type(i) = BOOK
-
기타 표현식
- SQL과 문법이 같은 식
- BETWEEN, LIKE, IS NULL
- EXISTS, IN
- AND, OR, NOT
- =, >, >=, <, <=, <>
6. 조건식
-
기본 CASE
select case when m.age <= 10 then '학생요금' when m.age >= 60 then '경로요금' else '일반요금' end from Member m
-
COALESCE - 하나씩 조회해서 Null 이 아니면 반환
select coalesce(m.username,'이름 없는 회원') from Member m
-
NULLIF - 두 값이 같으면 Null 반환, 다르면 첫번째 값 반환
select NULLIF(m.username, '관리자') from Member m
7. 기본 함수와 사용자 정의 함수
-
기본함수
종류 CONCAT SUBSTRING TRIM LOWER, UPPER LENGTH LOCATE ABS, SQRT, MOD SIZE, INDEX(JPA 용도) -
사용자 정의 함수
- 사용하는 DB 방언을 상속 받고, 사용자 정의 함수를 등록한다.