복습
https://shins99.tistory.com/117
JPQL (Java Persistence Query Language)
- JPQL은 엔티티 객체를 대상으로 하는 쿼리 언어
- JPQL의 문법 ex (나이가 18살 이상인 유저를 조회)
select u from User as u where u.age > 18
- JPQL은 SQL과 유사한 구문을 사용
JPQL 문법 특징
- 엔티티 클래스 이름, 엔티티 필드의 대소문자가 일치해야 함 ( 즉, 유저의 나이를 조회하는데 나이 필드가 age면 Age가 아닌 age로 작성 )
- JPQL 키워드는 대소문자 구분하지 않음. (SELECT, select, From, from)
- 엔티티 객체를 대상으로 하는 쿼리이므로 엔티티 이름을 사용 ( 테이블 이름 X )
- 별칭은 필수 (여기서는 u), (as는 생략가능하다.)
- SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않음
- JPQL은 결국 SQL로 변환
JPQL 기본 문법
집합과 정렬
COUNT, SUM, AVG, MAX, MIN 과 같은 집합 함수를 사용하여 결과를 집계할 수 있음
|
select |
|
COUNT(u), // 유저 수 |
|
SUM(u.age), // 나이 합 |
|
AVG(u.age), // 평균 나이 |
|
MAX(u.age), // 최대 나이 |
|
MIN(u.age) // 최소 나이 |
|
from User u |
GROUP BY, ORDER BY 를 사용하여 엔티티의 필드로 그룹화하고, HAVING 절을 사용해 그룹 조건을 적용 가능
|
// 각 나라별 유저 수 |
|
SELECT u.country, COUNT(u) FROM User u GROUP BY u.country |
|
|
|
// 각 나라별 유저 수가 > 100 |
|
SELECT u.country, COUNT(u) FROM User u GROUP BY u.country HAVING COUNT(u) > 100 |
프로젝션 (SELECT 절에 조회할 대상을 지정)
프로젝션 대상으로는 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자 등 기본 데이터 타입)이 있다.
|
SELECT m FROM Member m // 엔티티 프로젝션 |
|
SELECT m.address FROM Member m // 임베디드 타입 프로젝션 |
|
SELECT m.username, m.age FROM Member m // 스칼라(숫자, 문자, 날짜와 같은 기본 데이터 타입) 타입 프로젝션 |
|
select distinct m.username, m.age from Member.m // 중복값이 있을 경우 DISTINCT로 중복 제거 가능 |
Join
- JPQL에서 조인은엔티티 간의 관계로 수행되며 주로 일대일, 일대다, 다대일, 다대다 관계를 조회할 때 사용
- JPQL 조인은 연관된 필드를 기준으로 조인하며 외래 키를 통해 자동으로 맵핑
내부 조인 (INNER JOIN)
- 연관 관계가 맺어진 엔티티들에 대한 Inner Join을 말함 (INNER 는 생략가능)
- 특정 엔티티 간의 관계를 기반으로 일치하는 결과만 반환
아래 쿼리에서는 u.group을 기준으로 User와 Group 엔티티가 결합되며, 일치하는 결과만 반환
SELECT u, g FROM User u JOIN u.group g
- 내부 조인을 사용할 때는 반드시 연결할 엔티티와 연관 필드가 정의되어야 함
(일치하는 결과를 찾지 못할 경우 결과에 포함되지 않음)
외부 조인 (LEFT OUTER JOIN , RIGHT OUTER JOIN)
- 한쪽 엔티티에 연결된 엔티티가 누락되어도 결과 반환을 보장 (OUTER는 생략 가능)
- LEFT JOIN: 왼쪽 엔티티는 모두 선택하고, 오른쪽 엔티티는 일치하는 것만 선택
- RIGHT JOIN: 오른쪽 엔티티는 모두 선택하고, 왼쪽 엔티티는 일치하는 것만 선택
아래 쿼리에서 "o.product"를 기준으로 Order와 Product 엔티티가 외부 조인되며, 일치하지 않더라도 Order 엔티티는 결과에 포함
SELECT o, p FROM Order o LEFT JOIN o.product p
세타 조인 (Cross Join)
- 연관 관계없는 엔티티를 조인하는 방법
- 두 엔티티 간의 모든 경우의 조합을 생성한 후, WHERE 절의 비교 조건에 따라 결과를 필터링
- 세타 조인은 일반적으로 두 테이블 간의 연관관계가 정의되지 않은 경우에 사용
(단, 내부(INNER) 조인만 가능).
SELECT u, p FROM User u, Product p WHERE u.id = p.sellerId
ON 절
- JPQL의 ON 절은 조인 조건을 구체화하기 위해 사용 ( JOIN 대상을 필터링 )
- User 엔티티와 연결된 Address 엔티티를 조회하며 특정 도시(city)에 속한 주소만 필터링하는 경우,
다음과 같은 JPQL 쿼리를 사용가능
SELECT u, a FROM User u LEFT JOIN u.address a ON a.city = '서울'
"u.address"를 기준으로, "a.city = '서울'" 이라는 조건으로 ON 절을 이용하여 원하는 도시에 속한 주소만 조회한 쿼리문
- 세타 조인은 내부 조인 방식만 가능하지만, ON절은 엔티티 간의 연관 관계가 없이도 외부 조인이 가능
(ON 절을 사용해 연관 관계가 없더라도 외부 조인 가능)
서브 쿼리
- 서브 쿼리(Subquery)는 한 개의 쿼리 안에서 다른 쿼리를 포함하는 기능
- 서브 쿼리는 주로WHERE 절, HAVING 절,SELECT절에서 사용되며, 부모 쿼리와 함께 중첩되어 작성됨
- 서브 쿼리를 사용하면복잡한 쿼리 연산을 가능하게 하고, 결과에 대한 추가 조건을 적용 가능
아래의 쿼리는 서브쿼리를 활용하여 모든 사용자의 평균 나이를 계산하고, 부모 쿼리는 평균 나이보다 많은 사용자를 반환하는 쿼리
SELECT u FROM User u WHERE u.age > (SELECT AVG(u2.age) FROM User u2)
- 서브쿼리에서 WEHER 절에서 사용할 수 있는 EXISTS, ALL, ANY, SOME, IN이 존재
(이 것을 사용하여 특정 조건에 부합하는 데이터를 필터링 가능)
EXISTS
- 부모 쿼리의 해당 레코드가 서브 쿼리 결과에 존재하는지 여부를 검사
만약 결과가 하나 이상 존재하면 참 ( NOT EXISTS은 반대 )
|
// User 엔티티와 연결된 Address 엔티티를 조회하며, "서울"에 위치한 주소가 해당 사용자에 존재하는지 확인 |
|
SELECT u FROM User u WHERE EXISTS (SELECT a FROM u.addresses a WHERE a.city = '서울') |
ALL
- 부모 쿼리의 값이 서브쿼리의 모든 결과 값과 지정된 비교 연산자에 따라 비교되어 참인 경우에 해당하는 값을 반환
|
// 부모 쿼리(직원의 연봉)가 서브쿼리에서 반환된 모든 값(Manager의 연봉)보다 큰 경우를 필터링하며, 해당하는 직원만 반환 |
|
SELECT e FROM Employee e WHERE e.salary > ALL (SELECT m.salary FROM Manager m) |
ANY, SOME
- ANY와 SOME는 같은 기능을 수행
- 부모 쿼리의 값이 서브쿼리의 결과 값 중 지정된 비교 연산자에 따라 참인 경우에 해당하는 값을 반환
|
// 부모 쿼리(직원의 연봉)가 서브쿼리에서 반환된 값 중 하나(Manager의 연봉)보다 큰 경우를 필터링하며, 해당하는 직원을 반환 |
|
SELECT e FROM Employee e WHERE e.salary > ANY (SELECT m.salary FROM Manager m) |
IN
- 서브쿼리의 결과 중 하나라도 같은 것이 있으면 참 ( NOT IN은 반대 )
- 서브 쿼리의 결과 중 일치하는 값을 가진 데이터를 모두 선택
|
// User 엔티티와 연결된 Address 엔티티를 조회하며, "서울"에 위치한 주소에 사는 사용자와 같은 나이를 가진 사용자를 조회 |
|
SELECT u FROM User u WHERE u.age IN (SELECT u2.age FROM User u2 WHERE u2.city = '서울') |
타입 표현
- 문자 : 'HELLO', 'She''s'
- 숫자 : 10L, 10D, 10F
- boolean : TRUE, FALSE
- ENUM : jpabook.MemberType.Admin (패키지명 포함)
- 엔티티 타입 : TYPE(m) = Member (상속 관계에서 사용)
조건식 - CASE
CASE 조건식은 다음과 같이 사용할 수 있다. (기본 SQL 문법이랑 별 차이가 없다.)
|
// 기본 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이 아니면 반환
- NULLIF : 두 값이 같으면 NULL 반환, 다르면 첫번째 값 반환
|
// 사용자 이름이 없으면 이름 없는 회원을 반환 |
|
select coalesce(m.username,'이름 없는 회원') from Member m |
|
|
|
// 사용자 이름이 "관리자"면 NULL을 반환하고 나머지는 본인의 이름 반환 |
|
select NULLIF(m.username, '관리자') from Member m |
기본 연산자
- 다양한 연산자를 사용하여 조건을 지정 가능
- 비교 연산자: =, <>, <, >, <=, >=
- 논리 연산자: AND, OR, NOT
- 멤버십 연산자: IN, NOT IN, ALL, ANY, SOME, EXISTS
- LIKE / BETWEEN ... AND: 패턴 매칭과 범위 검색을 위한 연산자
JPQL 기본 함수
- CONCAT() : 여러 문자열을 하나의 문자열로 혹은 여러 컬럼을 하나의 문자열로 합치는 함수
- SUBSTRING() : SUBSTRING(str,pos,len)의 형태로 사용하며 문자열을 자르는 함수
- TRIM() : 문자열에 공백을 제거하는 함수 ( 좌, 우 공백만 제거 )
- LOWER(), UPPER() : 문자를 소문자 대문자로 변경하는 함수
- LENGTH() : 문자열의 길이를 가져오는 함수
- LOCATE(substr, str) : str에 있는 문자열 substr의 검색 위치를 정수로 반환하는 함수 (substr이 str에 없으면 0 반환)
- ABS() : 절대값을 구하는 함수
- SQRT() : 제곱근을 반환하는 함수
- MOD(n, m) : n을 m으로 나눈 나머지를 반환하는 함수
- SIZE() : 컬렉션의 크기를 구하는 함수 (JPA에서 사용)
- INDEX() : LIST 타입 컬렉션의 위치값을 구하는 함수 (JPA에서 사용)
'[Spring Boot] > [JPA]' 카테고리의 다른 글
[JPA] Pilot Project 2 (29) | 2023.10.31 |
---|---|
[JPA] Pilot_Project 블로그 테마별 알아보기 (1) | 2023.10.30 |
[JPA] 임베디드 타입 (@Embeddable) (1) | 2023.10.28 |
[JPA] 영속성 전이 (0) | 2023.10.27 |
[JPA] 상속관계 매핑 (1) | 2023.10.26 |