JPA

JPQL 문법 1

쭈녁 2022. 12. 22. 22:41

JPQL 문법 기초

select m from Member as m where m.age > 18

 

엔티티와 속성은 대소문자를 구분한다. 엔티티와 인스턴스의 대소문자를 신경 써야한다. (Member, Team, age, name)

JPQL 키워드는 대소문자 구분을 하지 않는다. (SELECT, FROM, WHERE / 소문자도 가능)

테이블 명이 아닌 엔티티의 이름 사용한다. (Member = O / MEMBER = X)

별칭은 필수로 기입해야한다. (m) (as는 생략가능)

 

집합과 정렬

SQL에서 지원하는 아래와 같은 함수가 모두 가능하다.

select
  COUNT(m), //회원수
  SUM(m.age), //나이 합
  AVG(m.age), //평균 나이
  MAX(m.age), //최대 나이
  MIN(m.age), //최소 나이
  GROUP BY xx,
  HAVING xx,
  ORDER BY xx
from Member m


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

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

//반환타입이 Member 객체로 명확함
TypedQuery<Member> typedQuery = em.createQuery("select m from Member as m", Member.class);
//반환타입이 String과 int 2가지로 다름
Query query = em.createQuery("select m.name, m.age from Member as m");


프로젝트


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

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

  • SELECT m FROM Member m -> 엔티티 프로젝션 (Member 객체가 조회됨)
  • SELECT m.team FROM Member m -> 엔티티 프로젝션 (Member에 연관된 Team객체가 조회됨)
  • SELECT m.address FROM Member m -> 임베디드 타입 프로젝션 (Member의 인스턴스로 있는 Address라는 임베디드 타입이 조회됨)
  • SELECT m.username, m.age FROM Member m -> 스칼라 타입 프로젝션 (다른 여러가지 값이 함께 조회됨)  ->DISTINCT로 중복 제거 가능

여러 다른 타입의 값이 조회될 때

예시) SELECT m.username, m.age FROM Member m

 

1. Query 타입으로 조회

List nameAge = em.createQuery("select distinct m.name, m.age from Member as m").getResultList();

Object o = nameAge.get(0);

Object[] nameAgeResult = (Object[]) o;

System.out.println("name = " + nameAgeResult[0]);
System.out.println("age = " + nameAgeResult[1]);

2. Object[] 타입으로 조회

List<Object[]> nameAge2 = em.createQuery("select distinct m.name, m.age from Member as m").getResultList();
Object[] nameAgeResult2 = nameAge2.get(0);
System.out.println("name = " + nameAgeResult2[0]);
System.out.println("age = " + nameAgeResult2[1]);

3. new 명령어로 조회 : 단순 값을 DTO로 바로 조회

SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM Member m

  • 패키지 명을 포함한 전체 클래스 명 입력
  • 순서와 타입이 일치하는 생성자 필요
public class MemberDTO {
    private String name;
    private int age;

(MemberDTO)

List<MemberDTO> nameAge3 = em.createQuery("select distinct new jpql.MemberDTO(m.name, m.age) from Member as m").getResultList();

MemberDTO memberDTO = nameAge3.get(0);
System.out.println("memberDTO.getName() = " + memberDTO.getName());
System.out.println("memberDTO.getAge() = " + memberDTO.getAge());

 

Paging

  • setFirstResult(int startPosition) : 조회 시작 위치 (0부터 시작)
  • setMaxResults(int maxResult) : 조회할 데이터 수
  • 설정값 중 아래 설정값을 변경하면 데이터 베이스 방언에 맞게 JPA가 쿼리문을 작성해준다
    •  </property name="hibernate.dialect" value="org.hibernate.dialect.h2dialect">    
List<Member> paging = em.createQuery("SELECT m FROM Member m ORDER BY m.age desc", Member.class)
        .setFirstResult(0)
        .setMaxResults(10)
        .getResultList();

Join 


내부 조인:

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

 

내부 조인과 외부 조인 : 

해당 내용은 DB에 관한 내용이지만 간략하게 짚고 넘어가도록 하려한다.

 

INNER JOIN :  두 테이블을 외래키로 조인했을 때 조인 키가 있는 데이터만 남고 조인 키가 없어 조인되지 않는 데이터들은 조회해오지 않는 교집합 형태이다

LEFT or RIGHT JOIN : 과 같은 외부 조인은 SELECT되는 테이블의 데이터는 모두 가져오면서 조인 키로 Join되는 값은 붙혀 오는 형식의 합집합 형태이다.

이때 LEFT와 RIGHT에 따라 LEFT는 가져오는 값에 조인하는 값을 RIGHT는 조인하는 값에 가져오는 값을 붙히는 형태로 가져오고 JOIN 되지 않는 컬럼은 null로 채워진다.

 


ON절

1. 조인 대상 필터링

<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'

ON절을 활용하면 조인 대상을 특정 컬럼의 조건을 두어 Join할수 있다. 위 쿼리는 Member에 Team의 name이 A인 Team을 LEFT JOIN 하도록 하는 쿼리이다.

 


 2. 연관관계 없는 엔티티 외부 조인


<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


서브쿼리

WHERE,HAVING,SELECT 절에선 SQL과 같이 서브 쿼리가 가능하지만

FROM절에서는 불가능하다. JOIN을 통해 풀어내야한다.

 

예시)

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


서브쿼리에 지원되는 함수

  • [NOT] EXISTS (subquery): 서브쿼리에 결과가 존재하면 참
  • ALL , ANY , SOME (subquery)
  • ALL 모두 만족하면 참
  • ANY, SOME: 같은 의미, 조건을 하나라도 만족하면 참
  • [NOT] IN (subquery): 서브쿼리의 결과 중 하나라도 같은 것이 있으면 참

예시)

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의 타입표현

  • 문자: ‘HELLO’, ‘She’’s’
  • 숫자: 10L(Long), 10D(Double), 10F(Float)
  • Boolean: TRUE, FALSE
  • ENUM: jpabook.MemberType.Admin (경로와 패키지명 포함)
  • 엔티티 타입: TYPE(m) = Member (상속 관계에서 사용)
    • 조회 대상을 특정 자식으로 한정
    • 예) Item 중에 Book, Movie를 조회해라
select i from Item i
where type(i) IN (Book, Movie)
• [SQL]
select i from i
where i.DTYPE in (‘B’, ‘M’)

<상속관계에서의 엔티티 타입 지정>

SQL과 문법이 같은 식

  • EXISTS, IN
  • AND, OR, NOT
  • =, >, >=, <, <=, <>
  • BETWEEN, LIKE, IS NULL


조건식 CASE

  • 기본 조건문
select
 case when m.age <= 10 then '10세이하'
 when m.age >= 60 then '60세 이상'
 else '기타'
 end
from Member m
  • 단순 조건문
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 반환, 다르면 첫번째 값 반환

select NULLIF(m.username, '관리자') from Member m

JPQL 함수

  • CONCAT (2개의 문자를 합함)
  • SUBSTRING (글자 인덱스 중 a~b까지 글자를 잘라옴)
  • TRIM (공백 제거 lefttrim, rigthtrim)
  • LOWER, UPPER (대소문자 변경)
  • LENGTH (길이)
  • LOCATE (동일한 문자가 있는 자리수 반환)
  • ABS, SQRT, MOD - 절대값, 루트, 나머지값
  • SIZE, INDEX(JPA 용도) - 컬렉션의 크기와 인덱스 위치(위치값에 대한 정보는 변동 될 수 있기 때문에 안쓰는게 좋음)

사용자 정의 함수

  • 하이버네이트는 사용전 방언에 추가해야 한다.
  • 사용하는 DB 방언을 상속받고, 사용자 정의 함수를 등록한다.
select function('group_concat', i.name) from Item i


경로 표현식

  • 상태 필드(state field): 단순히 값을 저장하기 위한 필드 (ex: m.username)
  • 연관 필드(association field): 연관관계를 위한 필드
  • 단일 값 연관 필드: @ManyToOne, @OneToOne, 대상이 엔티티(ex: m.team)
  • 컬렉션 값 연관 필드: @OneToMany, @ManyToMany, 대상이 컬렉션(ex: m.orders)

 

경로표현 특징

  • 상태 필드(state field): 경로 탐색의 끝, 탐색을 할 수 없다.
  • 단일 값 연관 경로: 묵시적 내부 조인(inner join) 발생, 탐색이 가능하다.
  • 컬렉션 값 연관 경로: 묵시적 내부 조인 발생, 탐색이 불가능하다.
  • FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색 가능

묵시적 조인이란? 

  • 경로 표현식에 의해 묵시적으로 SQL 조인 발생 (내부 조인만 가능)
select m.team from Member m
//join 이 없이 Member을 통해 team 엔티티를 찾으러 가다보니 묵시적으로 inner조인을 수행함

명시적 조인을 써라

  • join 키워드 직접 사용
select m from Member m join m.team t
//해당 코드는 어떤 컬럼과 조인했고 어떤 테이블을 가져왔는지 명확하기 때문에 이렇게 코딩하는것을 권장.

'JPA' 카테고리의 다른 글

영속성 컨텍스트  (0) 2024.01.28
JPQL문법 2 (페치 조인,벌크 연산)  (0) 2022.12.23
JPA 쿼리 언어 종류  (1) 2022.12.22
값 타입 정리  (0) 2022.12.21
프록시와 연관관계 (즉시로딩/지연로딩)  (0) 2022.12.21