# [JPA] JPQL 문법 3 - 경둜 ν‘œν˜„μ‹, μ„œλΈŒ 쿼리, 쑰건식
Study Repository

[JPA] JPQL 문법 3 - 경둜 ν‘œν˜„μ‹, μ„œλΈŒ 쿼리, 쑰건식

by rlaehddnd0422

경둜 ν‘œν˜„μ‹

경둜 ν‘œν˜„μ‹μ€ .을 찍어 μ—”ν‹°ν‹° κ°„μ˜ 관계λ₯Ό ν‘œν˜„ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ˜λŠ” ν‘œν˜„μ‹μœΌλ‘œ 객체 κ·Έλž˜ν”„λ₯Ό νƒμƒ‰ν•˜λŠ” μž‘μ—…μ— μ‚¬μš©λ©λ‹ˆλ‹€.

  • μƒνƒœ ν•„λ“œ : λ‹¨μˆœνžˆ 값을 μ €μž₯ν•˜κΈ° μœ„ν•œ ν•„λ“œ(ν”„λ‘œνΌν‹°)
  • μ—°κ΄€ ν•„λ“œ : 연관관계λ₯Ό μœ„ν•œ ν•„λ“œμ™€ μž„λ² λ””λ“œ νƒ€μž…
    • 단일 κ°’ μ—°κ΄€ ν•„λ“œ : @ManyToOne , @OneToOne λ‹¨μΌ μ—”ν‹°ν‹° λŒ€μƒ 
    • μ»¬λ ‰μ…˜ κ°’ μ—°κ΄€ ν•„λ“œ : @OneToMany , @ManyToMany μ»¬λ ‰μ…˜ μ—”ν‹°ν‹° λŒ€μƒ
    • μž„λ² λ””λ“œ νƒ€μž…
@Entity
public class Orders {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ORDER_ID")
    private Long id; // μƒνƒœ ν•„λ“œ

    private int orderAmount; // μƒνƒœ ν•„λ“œ

    @Embedded
    private Address address; // μ—°κ΄€ν•„λ“œ ( μž„λ² λ””λ“œ νƒ€μž… )

    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;  // μ—°κ΄€ν•„λ“œ ( 단일 μ—”ν‹°ν‹° ) 

    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product; // μ—°κ΄€ν•„λ“œ ( 단일 μ—”ν‹°ν‹° )
}

@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id; // μƒνƒœ ν•„λ“œ

    private String name; // μƒνƒœ ν•„λ“œ
    private int age; // μƒνƒœ ν•„λ“œ

    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
	private Team team; // μ—°κ΄€ ν•„λ“œ ( 단일 μ—”ν‹°ν‹° ) 
}

@Entity
public class Team {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "TEAM_ID")
    private Long id; // μƒνƒœ ν•„λ“œ
    private String name; // μƒνƒœ ν•„λ“œ

    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<Member>(); // μ—°κ΄€ ν•„λ“œ ( μ—”ν‹°ν‹° μ»¬λ ‰μ…˜ )
}
  • μƒνƒœ ν•„λ“œ 쑰회 μ‹œ μƒνƒœ ν•„λ“œκ°€ 경둜 νƒμƒ‰μ˜ 끝으둜 더 이상 .으둜 탐색할 수 μ—†μŠ΅λ‹ˆλ‹€. ( m.username, m.age κΉŒμ§€λ§Œ κ°€λŠ₯ )
  • 단일 κ°’ μ—°κ΄€ν•„λ“œ 쑰회 μ‹œ λ¬΅μ‹œμ μœΌλ‘œ λ‚΄λΆ€ 쑰인이 λ°œμƒν•©λ‹ˆλ‹€. 단일 κ°’ μ—°κ΄€ κ²½λ‘œλŠ” 계속 탐색이 κ°€λŠ₯ν•©λ‹ˆλ‹€. ( o.product.name )  
  • μ»¬λ ‰μ…˜ κ°’ μ—°κ΄€ν•„λ“œ 쑰회 μ‹œμ—λ„ λ§ˆμ°¬κ°€μ§€λ‘œ λ¬΅μ‹œμ  λ‚΄λΆ€ 쑰인이 λ°œμƒν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ 단일 κ°’κ³Ό 달리 μ»¬λ ‰μ…˜ κ°’ μ—°κ΄€ν•„λ“œ 쑰회의 경우 계속적인 탐색이 λΆˆκ°€λŠ₯ν•©λ‹ˆλ‹€. ( t.members.name X )
    • JPQL을 λ‹€λ£¨λ©΄μ„œ 많이 ν•˜λŠ” μ‹€μˆ˜λŠ” μ»¬λ ‰μ…˜ κ°’μ—μ„œ 경둜 탐색을 μ‹œλ„ν•˜λŠ” 것
    • FROM μ ˆμ—μ„œ 쑰인을 톡해 별칭을 μ–»μœΌλ©΄ λ³„μΉ­μœΌλ‘œ 탐색해야 ν•©λ‹ˆλ‹€.
// μ»¬λ ‰μ…˜μ˜ 계속적 탐색은 λΆˆκ°€λŠ₯
SELECT t.members.name
FROM Team t 

// 쑰인을 톡해 별칭을 μ–»μœΌλ©΄ 탐색해야 함
SELECT m.name
FROM Team t INNER JOIN t.members m

 

λ¬΅μ‹œμ  쑰인 μ˜ˆμ‹œ 

// JPQL
SELECT m.team ( 연관관계 단일 μ—”ν‹°ν‹° 쑰회 : λ¬΅μ‹œμ  λ‚΄λΆ€ 쑰인 λ°œμƒ ) 
FROM Member m

// μ‹€ν–‰λ˜λŠ” SQL
SELECT t
FROM Team t INNER JOIN Member m ON m.team_id = t.id

μ„œλΈŒ 쿼리

SQLκ³Ό λ§ˆμ°¬κ°€μ§€λ‘œ JPQL도 μ„œλΈŒ 쿼리λ₯Ό μ§€μ›ν•©λ‹ˆλ‹€. 단 JPQLμ—μ„œλŠ” select , from μ ˆμ—λ„ μ„œλΈŒ 쿼리λ₯Ό μ‚¬μš©ν•  수 μžˆλŠ” SQLκ³Ό 달리  where, having μ ˆμ—λ§Œ μ„œλΈŒ 쿼리λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

JPQL μ„œλΈŒ 쿼리 ν•¨μˆ˜

  • 1. [NOT] EXISTS (subquery) : μ„œλΈŒ 쿼리의 κ²°κ³Όκ°€ μ‘΄μž¬ν•˜λŠ” 경우 μ°Έ 리턴, NOT EXISTS은 λ°˜λŒ€
    • select m from Member m where exists (select t from m.team t where t.name = 'νŒ€A' ) 
    • -> νŒ€ 이름이 'νŒ€A'κ°€ μ†Œμ†μΈ νšŒμ› 쑰회
    • select m from Member m where not exists (select t from m.team t whrer t.name='νŒ€A')
    • -> νŒ€ 이름이 'νŒ€A'κ°€ μ•„λ‹Œ μ†Œμ†μ˜ νšŒμ› 쑰회
  • 2. [ALL | ANY | SOME] (<,=,>,>=,<=) (subquery) 
    • ALL 쑰건식 (subquery) : μ„œλΈŒμΏΌλ¦¬κ°€ 쑰건식 λͺ¨λ‘ λ§Œμ‘±ν•˜λ©΄ μ°Έ
    • select o from Order o where o.orderAmount > ALL (select p.stockAmount from Product p)
    • -> λͺ¨λ“  μƒν’ˆμ˜ μž¬κ³ λŸ‰λ³΄λ‹€ μ£Όλ¬ΈλŸ‰μ΄ λ§Žμ€ μ£Όλ¬Έλ“€ 쑰회
    • 3. ANY,SOME 쑰건식 (subquery) : μ„œλΈŒμΏΌλ¦¬κ°€ 쑰건을 ν•˜λ‚˜λΌλ„ λ§Œμ‘±ν•˜λ©΄ μ°Έ
      • -> select m from Member m where m.team = ANY  (select t from Team t)
      • -> μ–΄λŠ νŒ€μ΄λ“  νŒ€μ— μ†Œμ†λœ νšŒμ› 쑰회
  • 4. [NOT] IN (subquery)
    • μ„œλΈŒ 쿼리의 κ²°κ³Ό 쀑 ν•˜λ‚˜λΌλ„ 같은 것이 있으면 μ°Έ.
    • select t from Team t where t IN (select t2 from Team t2 JOIN t2.members m2 where m2.age >= 20 )
    • 20μ„Έ 이상을 λ³΄μœ ν•œ νŒ€ 

쑰건식

νƒ€μž… ν‘œν˜„

  • λ¬ΈμžλŠ” μž‘μ€ λ”°μ˜΄ν‘œλ‘œ κ°μ‹Έμ„œ ν‘œν˜„ν•©λ‹ˆλ‹€.
  • μˆ«μžλŠ” νƒ€μž…λ³„ Long의 경우 L, Double의 경우 D, Float의 경우 Fλ₯Ό λΆ™μ—¬ ν‘œν˜„ν•©λ‹ˆλ‹€. ex ) 1L,2D,3F 
  • λ‚ μ§œλŠ” DATE의 경우 {d '2023-05-10'}, TIME의 경우 {t '18-17-05'} : 18μ‹œ 17λΆ„ 5초, DATETIME의 경우 {ts '2023-05-10 18-17-05.123'}으둜 ν‘œν˜„
  • Boolean은 TRUE, FALSE둜 ν‘œν˜„

μ—°μ‚°μž μš°μ„ μˆœμœ„

1. 경둜 탐색 μ—°μ‚° (.)

2. μˆ˜ν•™ μ—°μ‚° : +,-,*,/ λ“±

3. 비ꡐ μ—°μ‚°

4. 논리 μ—°μ‚°

논리연산과 비ꡐ식

  • 비ꡐ식 :>,<, <=, >=, =, <>( 두 값이 μ„œλ‘œ λ‹€λ₯Έμ§€ νŒλ‹¨, != 의 JPQL 방식 ν‘œν˜„ ) 
  • 논리 μ—°μ‚° : AND, OR, NOT

Between, IN, LIKE 식

  • Between 식: X BETWEEN A AND B  ➑️ X 값이 A와 B 사이에 μžˆλŠ” 경우 μ°Έ
  • IN 식 : X IN (예제)  βž‘️ X와 같은 값이 μ˜ˆμ œμ— ν•˜λ‚˜λΌλ„ μžˆλŠ” 경우 μ°Έ 
  • LIKE 식 : X LIKE [νŒ¨ν„΄ κ°’]  βž‘️ Xκ°€ νŒ¨ν„΄κ°’κ³Ό μΌμΉ˜ν•˜λ©΄ μ°Έ
    • νŒ¨ν„΄ κ°’ μ˜ˆμ‹œ
      • '%νšŒμ›%' : 'νšŒμ›'을 ν¬ν•¨ν•œ λ¬Έμžμ—΄ (νšŒμ›μœΌλ‘œ μ‹œμž‘, λλ‚˜λŠ” 것도 ν¬ν•¨ν•©λ‹ˆλ‹€. ex) κΉ€νšŒμ›, κΉ€νšŒμ›κΉ€, νšŒμ›, νšŒμ›1) 
      • '%νšŒμ›' : 'νšŒμ›'으둜 λλ‚˜λŠ” λ¬Έμžμ—΄ (ex) κΉ€νšŒμ›, AνšŒμ›)
      • 'νšŒμ›%' : 'νšŒμ›'으둜 μ‹œμž‘ν•˜λŠ” λ¬Έμžμ—΄ (ex) νšŒμ›1, νšŒμ›AA)
      • '_νšŒμ›' : 'νšŒμ›'으둜 λλ‚˜λ˜, 언더라인 개수만큼만 μ•žμ— λ¬Έμžμ—΄λ‘œ μ±„μ›Œμ§„ λ¬Έμžμ—΄ (ex) _νšŒμ› : AνšŒμ›, 1νšŒμ› )
      • 'νšŒμ›_' : 'νšŒμ›'으둜 μ‹œμž‘ν•˜λ˜, 언더라인 개수만큼만 뒀에 λ¬Έμžμ—΄λ‘œ μ±„μ›Œμ§„ λ¬Έμžμ—΄ (ex) νšŒμ›_ : νšŒμ›1, νšŒμ›A )
      •  '_νšŒμ›_' : 'νšŒμ›'을 ν¬ν•¨ν•œ λ¬Έμžμ—΄μ΄λ˜, 언더라인 개수만큼만 λ¬Έμžμ—΄λ‘œ μ±„μ›Œμ§„ λ¬Έμžμ—΄ (ex) _νšŒμ›__ : 1νšŒμ›22, AνšŒμ›BB)

μ»¬λ ‰μ…˜ 식

μ»¬λ ‰μ…˜ 식은 μ»¬λ ‰μ…˜μ—λ§Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 

 

(μ»¬λ ‰μ…˜ κ°’ μ—°κ΄€κ²½λ‘œ) IS [NOT] EMPTY 

  • μ»¬λ ‰μ…˜μ΄ λΉ„μ–΄μžˆλŠ” 경우 μ°Έ , NOT은 λΉ„μ–΄μžˆμ§€ μ•Šμ€ 경우 μ°Έ
  • SELECT m FROM Member m WHERE m.orders is not empty
  • -> 주문이 ν•˜λ‚˜λΌλ„ μžˆλŠ” νšŒμ› 쑰회

(μ—”ν‹°ν‹° or κ°’) [NOT] member of (μ»¬λ ‰μ…˜ κ°’ μ—°κ΄€κ²½λ‘œ)

  • μ—”ν‹°ν‹°λ‚˜ 값이 μ»¬λ ‰μ…˜μ— ν¬ν•¨λ˜μ–΄ 있으면 μ°Έ
  • SELECT t FROM Team t where :memberParam member of t.members
  • -> memberParam이 t.members의 멀버 쀑 ν•˜λ‚˜μΈ λͺ¨λ“  νŒ€μ„ 선택 

슀칼라 식

μŠ€μΉΌλΌλŠ” 숫자, 문자, λ‚ μ§œ, case, μ—”ν‹°ν‹° νƒ€μž… 같은 κ°€μž₯ 기본적인 νƒ€μž…λ“€μž…λ‹ˆλ‹€.

슀칼라 νƒ€μž…μ— μ‚¬μš©ν•˜λŠ” 식을 μ•Œμ•„λ΄…μ‹œλ‹€.

 

λ¬Έμžν•¨μˆ˜

1. concat(문자1,문자2) : 문자λ₯Ό κ²°ν•©

2. substring(λ¬Έμžμ—΄, μœ„μΉ˜, 길이) : μœ„μΉ˜λΆ€ν„° μ‹œμž‘ν•΄ 길이만큼 substring κ΅¬ν•˜κΈ°

3. upper(문자),lower(문자) : 문자λ₯Ό λŒ€λ¬Έμž, μ†Œλ¬Έμžλ‘œ λ³€κ²½

4. length(문자) : λ¬Έμžμ—΄ 길이 리턴

5. locate(μ°Ύμ„λ¬Έμž, 원본 문자, κ²€μƒ‰μ‹œμž‘μœ„μΉ˜) : κ²€μƒ‰μ‹œμž‘μœ„μΉ˜λΆ€ν„° μ‹œμž‘ν•΄μ„œ μ°Ύμ€λ¬Έμžμ˜ μ‹œμž‘ 인덱슀 리턴, λͺ» 찾으면 0 리턴 

 

μˆ˜ν•™ν•¨μˆ˜

1. abs(식) : μ ˆλŒ“κ°’ 리턴

2. sqrt(식) : 제곱근 리턴

3. mod(μˆ˜ν•™μ‹, λ‚˜λˆŒ 수 ) : λ‚˜λ¨Έμ§€ 리턴

4. size(μ»¬λ ‰μ…˜ κ°’ μ—°κ΄€ κ²½λ‘œμ‹) : μ»¬λ ‰μ…˜μ˜ 크기 리턴

5. index(별칭) : μ»¬λ ‰μ…˜ νƒ€μž…μ˜ μœ„μΉ˜κ°’ 리턴 ex) t.members m where index(m) > 3

 

λ‚ μ§œν•¨μˆ˜

1. CURRENT_DATE : ν˜„μž¬ λ‚ μ§œ

2. CURRENT_TIME : ν˜„μž¬ μ‹œκ°„

3. CURRENT_TIMESTAMP : ν˜„μž¬ λ‚ μ§œμ™€ μ‹œκ°„

 

μ’…λ£Œ 이벀트 쑰회

SELECT e 
FROM Event e
WHERE e.endDate < CURRENT_DATE

CASE 식

νŠΉμ • 쑰건에 따라 λΆ„κΈ°ν•  λ•Œ CASE 식 μ‚¬μš©.

1. κΈ°λ³Έ CASE 

문법

CASE
	[when <쑰건식> them <μŠ€μΉΌλΌμ‹>}
   	...
    ELSE <μŠ€μΉΌλΌμ‹>
END

μ‚¬μš© μ˜ˆμ‹œ 

SELECT
	CASE WHEN m.age <= 10 then 'ν•™μƒμš”κΈˆ'
    	WHEN m.age >=60 then 'κ²½λ‘œμš”κΈˆ'
        else 'μΌλ°˜μš”κΈˆ'
	END
FROM Member m

2. μ‹¬ν”Œ CASE

μžλ°”μ˜ switch caaseλ¬Έκ³Ό λΉ„μŠ·ν•©λ‹ˆλ‹€. 쑰건 λŒ€μƒμ„ μ‚¬μš©ν•  경우

CASE <μ‘°κ±΄λŒ€μƒ>
	[when <μŠ€μΉΌλΌμ‹1> then <μŠ€μΉΌλΌμ‹2>}
    ELSE <μŠ€μΉΌλΌμ‹>
END

μ‚¬μš© μ˜ˆμ‹œ

SELECT
	CASE t.name
	    WHEN 'νŒ€A' then 'μΈμ„Όν‹°λΈŒ100%'
    	WHEN 'νŒ€B' then 'μΈμ„Όν‹°λΈŒ120%'
        else 'μΈμ„Όν‹°λΈŒ105%'
	END
FROM Team t

3. COALESCE

μŠ€μΉΌλΌμ‹μ„ μ°¨λ‘€λŒ€λ‘œ μ‘°νšŒν•΄μ„œ null이 μ•„λ‹ˆλ©΄ 리턴

 

문법

COALESCE(<μŠ€μΉΌλΌμ‹>, {<μŠ€μΉΌλΌμ‹>}+)

μ‚¬μš©μ˜ˆμ‹œ

m.username이 null이면 '이름 μ—†λŠ” νšŒμ›'을 리턴

SELECT coalesce(m.username,'이름 μ—†λŠ” νšŒμ›')
FROM Member m

4. NULLIF

문법 

μŠ€μΉΌλΌμ‹ 두 개λ₯Ό λΉ„κ΅ν•΄μ„œ 두 값이 κ°™μœΌλ©΄ null을 리턴, λ‹€λ₯΄λ©΄ 첫 번째 값을 리턴

NULLIF (<μŠ€μΉΌλΌμ‹>, <μŠ€μΉΌλΌμ‹>)

μ‚¬μš©μ˜ˆμ‹œ

SELECT NULLIF(m.username,'κ΄€λ¦¬μž') 
FROM Member m

 m.username이 κ΄€λ¦¬μžμ΄λ©΄ null 리턴, else m.username 리턴

 

 

<참고자료>

λΈ”λ‘œκ·Έμ˜ 정보

Study Repository

rlaehddnd0422

ν™œλ™ν•˜κΈ°