BE/JPA

[JPA] 16. JPQL - 1편

멍목 2022. 5. 1. 17:33
반응형

자바 ORM 표준 JPA 프로그래밍

 

 

 

 

 

 

이 포스팅에서 작성하는 내용은 자바 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

 

반응형