JPQL 기본 문법

2025. 4. 7. 17:25·JPA
목차
  1. JPQL 문법은 어떻게 될까?
  2. JPQL 기본 문법
  3. 프로젝션 (Projection)
  4. 페이징 API
  5. 조인 (JOIN)
  6. 서브 쿼리 (Subquery)
  7. JPQL 각 타입 표현식 & 기타식 & 조건 CASE 식 정리

 

 

 


 

JPQL 문법은 어떻게 될까?

 

 


 

 

 

 

JPQL 기본 문법

 

--

JPQL의 문법은 SQL과 거의 비슷하다. (똑같다고 생각해도 무방)

 

문법 형식

SELECT 컬럼(엔티티 필드) FROM 엔티티명 [AS 별칭] 
[WHERE 조건]
[GROUP BY 그룹핑 기준]
[HAVING 그룹핑 조건]
[ORDER BY 정렬 기준]

 

예시 코드

String jpql = "SELECT m.name FROM Member m";
List<String> names = em.createQuery(jpql, String.class)
                       .getResultList();

 

  • 엔티티와 속성은 대소문자 구분 O
  • JPQL 키워드는 대소문자 구분 X
  • 엔티티 객체를 대상으로 쿼리를 작성하는 것으로 데이블 이름이 아닌 엔티티 이름을 사용
  • 별칭은 필수  (Member를 m으로 별칭 하는 것처럼 / AS는 생략 가능)

 

 

TypedQuery<T>, Query 반환 타입

  • TypeQuery<T>   :   반환 타입이 명확할 때 사용
  • Query   :   반환 타입이 명확하지 않을 때 사용

예시 코드

TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);

Query query = em.createQuery("SELECT m.username, m.age from Member m");
// 엔티티 리스트 조회 (TypedQuery)
TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);
List<Member> members = query.getResultList();  
// 결과: List<Member>
// 여러 개의 필드 조회 (Query)
Query query = em.createQuery("SELECT m.name, m.age FROM Member m");
List<Object[]> results = query.getResultList();

for (Object[] row : results) {
    String name = (String) row[0];
    Integer age = (Integer) row[1];
    System.out.println("이름: " + name + ", 나이: " + age);
}

 

 

 

결과 조회 API

  • getResultList()   :   결과가 하나 이상일 때 리스트로 반환 (결과가 없으면 빈 리스트 반환)
  • getSingleResult()   :   결과가 정확히 하나인 단일 객체로 반환 (결과가 둘 이상이면 에러 발생)
    (결과 없을 때  =  NoResultException 발생 / 둘 이상일 때  =  NonUniqueResultException 발생)

 

예시 코드

TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);

List<Member> resultList = query.getResultList();

Member result = query.getSingleResult();

 

 

 

파라미터 바인딩

쿼리에 직접 값을 넣는 대신,

실행 시점에 값을 안전하게 주입하는 방법으로

이름, 위치 기준으로 바인딩이 가능하다.

 

이름 기반의 파라미터 바인딩  예시 코드 ( :기호를 사용 )

TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m where m.username = :username", Member.class);

query.setParameter("username", "An");        //username에서 An인 값을 찾아온다.

Member singleResult = query.getSingleResult();


// 참고. 위 코드를 메서드 체인을 통해 깔끔하게 작성 가능
Member result = em.createQuery("SELECT m FROM Member m where m.username = :username", Member.class)
                  .setParameter("username", "An")
                  .getSingledResult();
// 실행되는 SQL문
select
   m.id as id,
   m.age as age,
   m.TEAM_ID as TEAM_ID,
   m.username as username
from
   Member m
where
   m.username = An
  • :name 처럼 이름을 지정하여 가독성 증가
  • 순서를 신경 쓰지 않아도 되므로 유지보수성 증가
  • 추천 O

 

 

위치 기반의 파라미터 바인딩  예시 코드 ( ?기호를 사용 )

Member result = em.createQuery("SELECT m FROM Member m where m.username = ?1", Member.class)
                  .setParameter(1, "An")   // 1번째 파라미터에 "An" 대입
                  .getSingledResult();
  • ?1, ?2 처럼 위치(순서)로 값을 바인딩
  • 순서를 신경 써야 하므로 유지보수성이 낮음
  • 추천 X

--

 

 

 

 

프로젝션 (Projection)

 

--

프로젝션은

SELECT 절에서 조회할 대상을 지정하는 것으로

엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자 등 기본 데이터 타입), DTO를 지정한다.

(DISTINCT 키워드로 중복 제거도 가능)

 

// m은 Member 엔티티를 의미  =  엔티티 프로젝션
SELECT m FROM Member m

// m.team은 Team 엔티티를 의미  =  엔티티 프로젝션
SELECT m.team FROM Member m

// m.address는 따로 만들어 놓은 임베디드를 의미  =  임베디드 타입 프로젝션
SELECT m.address FROM Member m

// m.username과 m.age는 String과 int 타입을 의미  =  스칼라 타입 프로젝션
SELECT m.username, m.age FROM Member m

// new 키워드를 사용하여 해당 엔티티의 DTO 생성자를 호출하여 DTO 객체로 직접 변환하여 조회  =  DTO 프로젝션
SELECT new com.example.MemberDTO(m.name, m.age) FROM Member m
new 키워드를 통해 JPQL에서 DTO 객체로 직접 변환하여 조회하는 방식은
단순 값을 DTO로 바로 조회하는 방법으로 DTO 타입으로 조회한다.
이를 작성할 때 패키지 명을 포함한 전체 클래스 명을 입력해야 하며,
순서와 타입이 일치하는 생성자가 해당 DTO에 필요하다.

가독성이 좋고, 타입 캐스팅이 필요 없어 가장 깔끔한 방법이다.

--

 

 

 

 

페이징 API

 

--

JPA에서 대량의 데이터를 효율적으로 조회하기 위해 제공하는 기능으로

결과의 개수를 제한하고 특정 위치에서 조회할 수 있다.

(ex. 게시판에서 총 100개의 데이터가 존재하면 이를 한 페이지당 10개씩 총 10페이지로 나누고 원하는 페이지의 데이터만 조회 가능)

 

JPA에서는 페이징을 2개의 API로 모두 추상화했다.

 

페이징 API 메서드 종류

위 두 API를 사용하여 몇 번째 부터 몇 개의 데이터를 조회할지 정의할 수 있다.

 

예시 코드

// 10번째 데이터부터 총 20개의 데이터를 가져온다.
String jpql = "select m from Member m order by m.name desc";
List<Member> resultList = em.createQuery(jpql, Member.class)
                            .setFirstResult(10)
                            .setMaxResults(20)
                            .getResultList();

 

장점

  • 대량 데이터 조회 시 성능 최적화
  • 필요한 데이터만 조회하므로 불필요한 리소스 낭비 방지
  • 메모리 사용량 감소

--

 

 

 

 

조인 (JOIN)

 

--

JPQL의 조인은

기존 SQL의 조인과 실행되는 것이 동일하지만

엔티티를 중심으로 동작을 하다보니 객체 스타일로 문법을 작성하는 차이점이 존재한다.

즉, 엔티티 객체 간의 관계를 기준으로 조인을 수행한다.

 

예시 코드

// 내부 조인  (m과 m안에 존재하는 team을 t로 조인)
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
대괄호로 표시한 INNER, OUTER는 생략 가능

 

 

 

ON 절

ON 절을 활용한 조인을 사용하면

조인할 때 조인 대상을 미리 필터링 할 수 있으며,

연관관계없는 엔티티를 내부, 외부 조인도 가능하다.

 

예시 코드

// 조인 대상을 미리 필터링 후 조인
// (Member와 Team을 조인하면서, Team의 name이 A인 Team만 조인)

// 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.TEAM_ID=t.id and t.name='A'
// 연관관계가 없는 엔티티를 외부 조인
// Member의 username과 Team의 name이 같은 대상의 외부 조인

// JPQL
SELECT m, t FROM Member m LEFT JOIN Team t on m.username = t.name

// SQL
SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.username = t.name

--

 

 

 

 

서브 쿼리 (Subquery)

 

--

JPQL에서도 서브 쿼리(쿼리 안에 쿼리)를 지원하지만

JPQL에서 사용하는 서브 쿼리는 한계가 존재한다.

  • JPA는 WHERE, HAVING 절에서만 서브 쿼리 사용 가능
    (SELECT 절에서도 가능 = 하이버네이트에서 지원)
  • FROM 절의 서브 쿼리는 하이버네이트 6부터 지원

 

서브 쿼리에서 지원하는 함수

- [NOT] EXISTS (서브쿼리)  :  서브 쿼리에 결과가 존재하면 참

- {ALL | ANY | SOME}(서브쿼리)  :  ALL : 모두 만족하면 참  /  ANY, SOME : 하나라도 만족하면 참

- [NOT] IN (서브쿼리)  :  서브 쿼리의 결과 중 하나라도 같은 것이 존재하면 해당하는 데이터 조회

 

예시 코드

// "팀A" 소속인 회원 조회
select m from Member m where exists (select t from m.team t where t.name = '팀A')

// 전체 상품의 각각 재고보다 주문량이 많은 주문을 조회
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)

--

 

 

 

 

JPQL 각 타입 표현식 & 기타식 & 조건 CASE 식 정리

 

--

타입 표현

  • 문자   :   'Hello',  'she''s'   ('를 표현하기 위해서는 ''두 번 작성)
  • 숫자   :   10L (= Long),  10D (= Double),  10F (= Float)
  • Boolean  :  TRUE, FALSE
  • ENUM   :   패키지경로.클래스명  (패키지명 포함해서 작성)
  • 엔티티   :   TYPE(m) = Member

 

 

기타 표현

  • SQL 문법과 동일
  • EXISTS, IN
  • AND, OR, NOT
  • =, >, >=, <, <=, <>
  • BETWEEN, LIKE, IS NULL

 

 

조건 (CASE 식)

기본 CASE 식 (범위에 해당)

// m.age가 10이하이면 "학생요금", 60이상이면 "경로요금", 나머지는 "일반요금"
select
   case when m.age <= 10 then '학생요금'
        when m.age >= 60 then '경로요금'
        else '일반요금'
   end
from Member m

 

단순 CASE 식 (특정 값과 동일)

// t.name이 "팀A" 이면 "인센티브110%" "팀B"이면 "인센티브120%" 나머지는 "인센티브105%"
select
   case t.name
      when '팀A' then '인센티브110%'
      when '팀B' then '인센티브120%'
      else '인센티브105%'
   end
from Team t

 

COALESCE  (하나씩 조회하여 null이 아니면 반환)

// username이 없으면 ‘이름 없는 회원’을 반환, 있으면 username 반환
select coalesce(m.username,'이름 없는 회원') from Member m

 

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

// username이 ‘관리자’면 null 반환, 아닌 나머지는 본인의 이름을 반환
select NULLIF(m.username, '관리자') from Member m

--

 

 

 

 

 


참고 및 출처

  • https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

 

 

 

 

저작자표시 비영리 변경금지 (새창열림)

'JPA' 카테고리의 다른 글

객체지향 쿼리 언어(OOQL) 종류  (0) 2025.04.05
JPA의 데이터 타입  (0) 2025.04.04
영속성 전이 (CASCADE) (+ 고아 객체)  (0) 2025.04.03
즉시 로딩 및 지연 로딩 (+ JPA의 프록시)  (1) 2025.04.02
상속관계 매핑 (+@MappedSuperclass)  (1) 2025.04.01
  1. JPQL 문법은 어떻게 될까?
  2. JPQL 기본 문법
  3. 프로젝션 (Projection)
  4. 페이징 API
  5. 조인 (JOIN)
  6. 서브 쿼리 (Subquery)
  7. JPQL 각 타입 표현식 & 기타식 & 조건 CASE 식 정리
'JPA' 카테고리의 다른 글
  • 객체지향 쿼리 언어(OOQL) 종류
  • JPA의 데이터 타입
  • 영속성 전이 (CASCADE) (+ 고아 객체)
  • 즉시 로딩 및 지연 로딩 (+ JPA의 프록시)
아-니지
아-니지
아-니지
성장 기록.zip
아-니지
  • 분류 전체보기 (266)
    • Language (76)
      • Java (39)
      • Kotlin (0)
      • HTML (10)
      • CSS (17)
      • Java Script (10)
    • JPA (11)
    • Spring Boot (27)
    • QueryDSL (2)
    • SQL [DB] (8)
    • Docker (29)
    • AWS (19)
    • Git & GitHub (17)
    • DevOps (1)
    • Terminology (14)
    • CS (50)
      • 컴퓨터 구조 (12)
      • 운영체제 (11)
      • 자료구조 (11)
      • 알고리즘 (0)
      • 네트워크 (16)
    • Record (7)
      • 알고리즘 풀이 (4)
      • 자바 메서드 (3)
    • Self Q&A (5)
hELLO· Designed By정상우.v4.5.3
아-니지
JPQL 기본 문법

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.