반응형
이 포스팅에서 작성하는 내용은 자바 ORM 표준 JPA 프로그래밍 (김영한 지음) 에서 발췌하였습니다.
1. JPQL 소개
- JPQL 은 객체 지향 쿼리 언어임. 따라서 테이블을 대상으로 쿼리를 날리는 것이 아닌 엔티티 객체를 대상으로 쿼리를 날려야함.
- JPQL은 SQL을 추상화해서 특정 DB에 의존하지 않음
- 작성한 JPQL은 결국 SQL로 변환됨
2. JPQL 문법
- select m from Member as m where m.age > 18 (18살을 넘은 회원을 조회)
- 엔티티와 속성은 대소문자 구분 O
- JPQL 키워드는 대소문자 구분 X
- 엔티티 이름(@Entity)으로 사용해야함. 테이블 이름이 아님
- 별칭은 필수 (m) (as 생략 가능)
- TypeQuery : 반환 타입이 명확할 때 사용
- Query : 반환 타입이 명확하지 않을 때 사용
- 결과 조회
- query.getResultList() : 결과가 하나 이상일 때, 리스트 반환 (결과가 없으면 빈 리스트 반환)
- query.getSingleResult() : 결과가 정확히 하나일 때 반환 (단일 객체 반환)
- 결과가 없으면 → javax.persistence.NoResultException
- 결과가 둘 이상이면 → javax.persisitence.NonUniqueResultException
- 파라미터 사용 방법
TypedQuery<MemberJpql> query = em.createQuery("SELECT m FROM Member m WHERE m.username = :username", Member.class);
query.setParameter("username", "member1");
1) select
select ~
from ~
[where ~]
[groupby ~]
[having ~]
[orderby ~]
2) update
update ~
[where ~]
3) delete
delete ~
[where ~]
select
COUNT(m), // 회원 수
SUM(m.age), // 나이 합
AVG(m.age), // 평균 나이
MAX(m.age), // 최대 나이
MIN(m.age) // 최소 나이
from Member m
3. 프로젝션
- SELECT 절에 조회할 대상을 지정하는 것
- DISTINCT로 중복 제거 가능
- 프로젝션 대상 : 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자 등 기본 데이터 타입)
- SELECT m FROM Member m → 엔티티 프로젝션
- SELECT m.team FROM Member m → 엔티티 프로젝션
- SELECT m.address FROM Member m → 임베디드 타입 프로젝션 (참고. 기존에 Address라는 임베디드 타입을 생성한 적이 있음)
- SELECT m.username, m.age FROM Member m → 스칼라 타입 프로젝션
- 여러 값 조회
- SELECT m.username, m.age FROM Member m
- Query 타입으로 조회(반환타입이 명확하지 않을 때 사용하는 Query 타입)
- Object[] 타입으로 조회
- new 명령어로 조회
- 단순 값을 DTO로 바로 조회
- 패키지 명을 포함한 전체 클래스명 입력
- 순서와 타입이 일치하는 생성자 필요
4. 페이징
- JPA는 페이징을 다음 두 API로 추상화함(아래 두가지만을 이용해서 페이징 처리 가능)
- setFirstResult(int startPosition) : 조회 시작 위치(0부터 시작)
- setMaxResults(int maxResult) : 조회할 데이터의 수
5. 조인
- 내부 조인(SELECT m FROM Member m [INNER] JOIN m.team t
- 외부 조인(SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
- 세타 조인(SELECT count(m) FROM Member m, Team t WHERE m.username = t.name
- ON 절을 활용한 조인(JPA 2.1 부터 지원)
- 조인 대상 필터링
- 연관관계 없는 엔티티 외부 조인(하이버네이트 5.1부터)
6. 서브쿼리
- 일반적으로 알고있는 그 서브쿼리
- 서브 쿼리 지원 함수
- [NOT] EXISTS (subquery) : 서브쿼리에 결과가 존재하면 참
- {ALL | ANY | SOME} (subquery)
- ALL : 모두 만족하면 참
- ANY, SOME : 같은 의미로 조건을 하나라도 만족하면 참
- [NOT] IN (subquery) : 서브 쿼리의 결과 중 하나라도 같은 것이 있으면 참
- JPA 서브쿼리의 한계
- WHERE, HAVING 절에서만 서브 쿼리 사용 가능
- 하이버네이트에서는 SELECT 절에서도 사용 가능
- FROM 절의 서브쿼리는 현재 JPQL에서는 불가능하므로 조인으로 풀 수 있으면 조인으로 해결
/**** 서브쿼리 예제 ****/
// 나이가 평균보다 많은 회원
select m from Member m where m.age > (select avg(m2.age) from Member m2)
// 한 건이라도 주문한 고객
select m from Member m where (select count(o) from Order o where m = o.member) > 0
// 'TeamA'에 속한 회원 찾기
select m from Member m where exists (select t from m.team t where t.name = 'teamA')
// 전체 상품 각각의 재고보다 주문량이 많은 주문들
select o from Order o where o.orderAcount > ALL(select p.stcokAmount from Product p)
// 어떤 팀이든 팀에 속해있는 회원
select m from Member m where m.team = ANY(select t from Team t)
7. JPQL 타입 표현
- 문자 : 'HELLO', 'She'
- 숫자 : 10L(Long), 10D(Double), 10F(Float)
- Boolean, TRUE, FALSE (대소문자 구분X)
- ENUM : jpabook.MemberType.Admin
- JPQL에 ENUM을 사용할 때 ENUM 값만 넣는 것이 아닌, 값 앞에 패키지명 포함.
- 파라미터를 이용하면 평소에 사용하던 것 처럼 파라미터에 값을 넣어주면 됨.
- 엔티티 타입 : TYPE(m) = Member(상속관계에서 사용)
8. JPQL 기타
- SQL과 문법이 같은 식
- EXISTS, IN
- AND, OR, NOT
- =, >, >=, <, <=, <>
- BETWEEN, LIKE, IS NULL
9. 조건식
1) CASE 식
(1) 기본 CASE 식
SEELCT
CASE WHEN m.age <= 19 then '청소년'
CASE WHEN m.age >= 60 then '노인'
ELSE '일반'
END
FROM MEMBER m
(2) 단순 CASE 식
SELECT
CASE f.name
WHEN 'apple' THEN '사과'
WHEN 'peach' THEN '복숭아'
ELSE '기타'
END
FROM Fruit f
(3) COALESCE : 하나씩 조회해서 null 이 아니면 반환
// 사용자 이름이 null 이면 'No Named' 이름으로 반환
SELECT COALESCE(m.username, 'No Named') FROM Member m
(4) NULLIF : 두 값이 같으면 null 반환, 다르면 첫 번째 값 반환
// 사용자 이름이 '관리자'면 null 반환, 나머지는 본인 이름 반환
SELECT NULLIF(m.username, '관리자') FROM Member m
10. JPQL 기본 함수
1) 기본 함수
- CONCAT
- SUBSTRING
- TRIM
- LOWER, UPPER
- LENGTH
- LOCATE
- ABS, SQRT, MOD
- SIZE, INDEX(JPA 용도)
2) 사용자 정의 함수 호출
- 하이버네이트는 사용 전 방언에 추가해야 한다.
- 사용하는 DB방언을 상속받고, 사용자 정의 함수를 등록한다.
SELECT FUNCTION('get_my_last_name', m.username) FROM Member m
반응형
'BE > JPA' 카테고리의 다른 글
[JPA] PK 타입을 UUID로 사용하는 방법 (0) | 2022.05.09 |
---|---|
[JPA] 17. JPQL - 2편 (0) | 2022.05.04 |
[JPA] 15. 다양한 쿼리를 이용한 조회 (0) | 2022.04.26 |
[JPA] 14. 값 타입 (0) | 2022.04.25 |
[JPA] 13. 프록시와 연관관계 관리 (0) | 2022.04.21 |