[JPA] JPQL

[JPA] JPQL

자바 ORM 표준 JPA 프로그래밍 - 기본편

JPQL

기본 문법

select m from Member m where m.age > 18

엔티티와 속성은 대소문자를 구분한다. (Member, age)

JPQL 키워드는 대소문자를 구분하지 않는다.(SELECT, FROM, where)

엔티티 이름 사용, 테이블 이름이 아님(Member)

별칭(alias)는 필수(여기서는 Member의 m), as는 생략가능

집합과 정렬

select COUNT(m), SUM(m.age)... from Member m

GROUP BY, HAVING 지원

ORDER BY 지원

TypeQuery, Query

TypeQuery : 반환 타입이 명확할 때 사용

: 반환 타입이 명확할 때 사용 Query : 반환 타입이 명확하지 않을 때 사용

TypeQuery query = em.createQuery("select m from Member M", Member.class); Query query = em.createQuery("select m from Member M");

결과 조회 API

query.getResultList(): 결과가 하나 이상일 때, 리스트 반환. 결과가 없으면 빈 리스트 반환

리스트 반환. query.getSingleResult(): 결과가 정확히 하나 , 단일 객체 반환 결과가 없으면: javax.persistence.NoResultException(값이 없으면 error를 던져 별로임) 둘 이상이면: javax.persistence.NonUniqueResultException

, 단일 객체 반환

파라미터 바인딩

//이름 기반 파라미터 바인딩 Member member = em.createQuery("select m from Member M where m.name = :username", Member.class); .setParameter("username", "daniel") .getSingleResult(); //위치 기반 파라미터 바인딩(사용 X) Member member = em.createQuery("select m from Member M where m.name = ?1", Member.class); .setParameter(1, "daniel") .getSingleResult();

프로젝션

select 절에 조회할 대상을 지정하는 것

프로젝션 대상: 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자 등 기본데이터 타입)

select m from Member m → 엔티티 프로젝션

select m.team Member m → 엔티티 프로젝션

select m.address Member m → 임베디드 타입 프로젝션

select m.username, m.age from Member m → 스칼라 타입 프로젝션

DISTINCT로 중복 제거 가능

프로젝션 - 여러 값으로 조회

select m.username, m.age from Member m

Query 타입으로 조회

Object[] 타입으로 조회

new 명령어로 조회 단순 값을 DTO로 바로 조회: select new jpabook.jpql.UserDTO(m.username, m.age) from Member m 패키지명을 포함한 전체 클래스 명 입력 순서와 타입이 일치하는 생성자 필요

페이징 API

setFirstResult(int startPosition): 조회 시작 위치(0부터 시작)

setMaxResult(int maxResult): 조회할 데이터 수

방언(Dialect)를 이용해서 여러 데이터베이스와 호환

조인

내부조인: 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 절

ON절을 활용한 조인(JPA 2.1 부터 지원) 조인 대상 필터링 select m.t from Member m left join m.team t = on t.name = 'A' 연관관계 없는 엔티티 외부 조인(하이버네이트 5.1부터) select m, t from Member m left join Team t on m.username = t.name

서브 쿼리

[NOT] EXIST(subquery): 서브쿼리에 결과가 존재하면 참 [ALL | ANY | SOME] (subquery) ALL: 모두 만족하면 참 ANY, SOME: 같은 의미, 조건을 하나라도 만족하면 참

[NOT] IN (subquery): 서브쿼리의 결과 중 하나라도 같은 것이 있으면 참

한계 JPA는 where, having 절에서만 서브 쿼리 사용 가능 select 절 서브쿼리는 하버네이트에서 지원함 from 절 서브쿼리는 현재 jpql에서는 불가능(join으로 풀 수 있으면 풀어서 해결)

JPQL 타입 표현

문자: 'HELLO WORLD'

숫자: 10L(long), 10D(Double), 10F(Float)

Boolean: TRUE, FALSE

ENUM: test.MemberType.Member(패키지명 포함)

엔티티 타입: TYPE(m) = Member(상속 관계에서 사용)

조건식 - CASE 식

기본 CASE 식

select case when m.age <= 10 then '학생요금' when m.age >= 60 then '경로요금' else '일반요금' end from Member m

단순 CASE 식

select case t.name when '팀A' then '인센티브110%' when '팀B' then '인센티브120%' else '인센티브105%' end from Team t

COALESCE: 하나씩 조회해서 null이 아니면 반환

-- 사용자 이름이 없으면 이름 없는 회원을 반환 select coalesce(m.username, '이름 없는 회원') from Member m

NULLIF: 두 값이 같으면 null 반환, 다르면 첫번째 값 반환

-- 사용자 이름이 '관리자'면 null을 반환하고 나머지는 본인의 이름을 반환 select NULLIF(m.username, '관리자') from Member m

JPQL 기본함수

CONCAT(문자열 합치기)

SUBSTRING(문자열 자르기)

TRIM(공백제거)

LOWER, UPPER(대소문자)

LENGTH(길이)

LOCATE(위치 반환)

ABS, SQRT, MOD(절댓값, 제곱근, 나머지)

SIZE, INDEX(JPA 용도)

사용자 정의 함수 호출

하이버네이트는 사용전 방언에 추가해야한다.

사용하는 DB 방언을 상속받고, 사용자 정의 함수를 등록한다.

select function('group_concat', i.name) from Item i

from http://daniel-blog.tistory.com/33 by ccl(A) rewrite - 2021-08-08 10:01:35