[JPQL] left ( outer ) join

2021. 10. 5. 22:28ㆍBack-End μž‘μ—…μ‹€/Spring Framework

728x90
λ°˜μ‘ν˜•

πŸ“ŒJPQLκ³Ό left ( outer ) join

λͺ©λ‘ ν™”λ©΄μ—μ„œ κ²Œμ‹œκΈ€μ˜ 정보와 ν•¨κ»˜ λŒ“κΈ€μ˜ 수λ₯Ό 같이 κ°€μ Έμ˜€κΈ° μœ„ν•΄μ„œλŠ” λ‹¨μˆœνžˆ ν•˜λ‚˜μ˜ μ—”ν‹°ν‹° νƒ€μž…μ„ μ΄μš©ν•  수 μ—†λŠ” κ²ƒμ΄μ—μš”. 이에 λŒ€ν•œ ν•΄κ²°μ±… 쀑 ν•˜λ‚˜κ°€ 많이 μ‚¬μš©λ˜λŠ” JPQL의 Join(쑰인)을 μ΄μš©ν•΄μ„œ μ²˜λ¦¬ν•˜λŠ” κ²ƒμ΄μ—μš”.

 

 

 

μžλ°” ORM ν‘œμ€€ JPA ν”„λ‘œκ·Έλž˜λ°:μŠ€ν”„λ§ 데이터 예제 ν”„λ‘œμ νŠΈλ‘œ λ°°μš°λŠ” μ „μžμ •λΆ€ ν‘œμ€€ 데이터베이

COUPANG

www.coupang.com

"이 ν¬μŠ€νŒ…μ€ 쿠팑 νŒŒνŠΈλ„ˆμŠ€ ν™œλ™μ˜ μΌν™˜μœΌλ‘œ, 이에 λ”°λ₯Έ μΌμ •μ•‘μ˜ 수수료λ₯Ό μ œκ³΅λ°›μŠ΅λ‹ˆλ‹€."

 

 

         πŸ‘‰ left ( outer ) join

Spring Boot 2 Version 이후 ν¬ν•¨λ˜λŠ” JPA 버전은 μ—”ν‹°ν‹° 클래슀 내에 μ „ν˜€ μ™„κ΄€ 관계가 없더라도 쑰인을 μ΄μš©ν•  수 μžˆλŠ” κ²ƒμ΄μ—μš”. 쑰인을 ν•  λ•Œ 'INNER JOIN ν˜Ήμ€ JOIN' κ³Ό 같이 일반적인 쑰인을 μ΄μš©ν•  μˆ˜λ„ 있고, 'LEFT OUTER JOIN ν˜Ήμ€ LEFT JOIN'을 μ΄μš©ν•  μˆ˜λ„ μžˆλŠ” κ²ƒμ΄μ—μš”.

 

μ£Όλ‹ˆν•˜λž‘μ˜ SystemUseManul μ—”ν‹°ν‹° 클래슀의 λ‚΄λΆ€μ—λŠ” Member μ—”ν‹°ν‹° 클래슀λ₯Ό λ³€μˆ˜λ‘œ μ„ μ–Έν•˜κ³ , μ—°κ΄€ 관계λ₯Ό λ§Ίκ³  μžˆλŠ” κ²ƒμ΄μ—μš”. 이런 경우 SystemUseManul 의 writer λ³€μˆ˜λ₯Ό μ΄μš©ν•΄μ„œ 쑰인을 μ²˜λ¦¬ν•˜λŠ” κ²ƒμ΄μ—μš”.

 

 

getManualWithWriter() λŠ” SystemUseManual λ₯Ό μ‚¬μš©ν•˜κ³  μžˆμœΌλ‚˜, Member λ₯Ό 같이 μ‘°νšŒν•΄μ•Ό ν•˜λŠ” 상황인 κ²ƒμ΄μ—μš”. SystemUseManual ν΄λž˜μŠ€μ—λŠ” Memberμ™€μ˜ μ—°κ΄€ 관계λ₯Ό λ§Ίκ³  있기 λ•Œλ¬Έμ— m.writer와 같은 ν˜•νƒœλ‘œ μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” κ²ƒμ΄μ—μš”. 이처럼 내뢀에 μ—”ν‹°ν‹°λ₯Ό μ΄μš©ν•  λ•ŒλŠ” 'LEFT JOIN' λ’€μ— 'ON'을 μ΄μš©ν•˜λŠ” 뢀뢄이 μ—†λŠ” κ²ƒμ΄μ—μš”. μž‘μ„±ν•œ getManualWithWriter()λ₯Ό ν…ŒμŠ€νŠΈ μ½”λ“œλ‘œ 확인 ν•΄ λ³Όκ²Œμš”!

 

 

κ²°κ³Όλ₯Ό 보면 Lazy Loading (지연 λ‘œλ”©)을 μ‚¬μš©ν•˜μ—¬ μ²˜λ¦¬ν–ˆμœΌλ‚˜, μ‹€ν–‰λ˜λŠ” 쿼리λ₯Ό 보면 쑰인 μ²˜λ¦¬κ°€ λ˜μ–΄ ν•œ λ²ˆμ— SystemUseManual ν…Œμ΄λΈ”κ³Ό member ν…Œμ΄λΈ”μ„ μ΄μš©ν•˜λŠ” 것을 λ³Ό 수 μžˆλŠ” κ²ƒμ΄μ—μš”!

 

 

    πŸ“ μ—°κ΄€ 관계가 μ—†λŠ” Entity Join μ²˜λ¦¬μ—λŠ” on

SystemUseManual κ³Ό Member μ‚¬μ΄μ—λŠ” λ‚΄λΆ€μ μœΌλ‘œ μ°Έμ‘°λ₯Ό 톡해 μ—°κ΄€ 관계가 μžˆμ§€λ§Œ, SystemUseManual μ™€ Comment λŠ” 상황이 λ‹€λ₯Έ κ²ƒμ΄μ—μš”. Comment μͺ½μ΄ @ManyToOne으둜 μ°Έμ‘°ν•˜κ³  μžˆμ§€λ§Œ, SystemUseManual μž…μž₯μ—μ„œλŠ” Comment 객체듀을 μ°Έμ‘°ν•˜κ³  μžˆμ§€ μ•ŠκΈ° λ•Œλ¬Έμ— λ¬Έμ œκ°€ λ˜λŠ” κ²ƒμ΄μ—μš”. 이런 경우 직접 쑰인에 ν•„μš”ν•œ 쑰건은 'on'을 μ΄μš©ν•΄μ„œ μž‘μ„±ν•΄ μ£Όμ–΄μ•Ό ν•œλ‹΅λ‹ˆλ‹€!

'νŠΉμ • κ²Œμ‹œλ¬Όκ³Ό ν•΄λ‹Ή κ²Œμ‹œλ¬Όμ— μ†ν•œ λŒ“κΈ€μ„μ„ 쑰회' ν•΄μ•Ό ν•˜λŠ” 상황을 μƒκ°ν•˜λ©΄ SystemUseManual κ³Ό Comment ν…Œμ΄λΈ”μ„ μ‘°μΈν•΄μ„œ 쿼리λ₯Ό μž‘μ„±ν•˜κ²Œ λ©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ ν˜„μž¬ DB 내에 100번 κ²Œμ‹œκΈ€μ€ 두 개의 λŒ“ 글을 가지고 μžˆλ‹€κ³  κ°€μ •ν•  λ•Œ, 이λ₯Ό μˆœμˆ˜ν•œ SQL둜 μ²˜λ¦¬ν•œλ‹€λ©΄ λ‹€μŒκ³Ό 같이 μž‘μ„±ν•  수 μžˆλŠ” κ²ƒμ΄μ—μš”.

 

select systemUseManual.no, systemUseManual.title, systemUseManual.writer_email, manualCommentNo, commentContent
from systemUseManual left outer join SystemUseManualCommnet comment
on comment.systemUseManual .no = systemUseManual .no
where systemUseManual.no = 100;

 

μœ„μ˜ 쿼리λ₯Ό JPQL둜 μ²˜λ¦¬ν•˜λ©΄ μ•„λž˜μ™€ 같은 κ²ƒμ΄μ—μš”!

 

 

μ—°κ°„ 관계가 μžˆλŠ” κ²½μš°μ™€ 비ꡐ해 보면 쀑간에 'on'이 μ‚¬μš©λ˜λ©΄μ„œ 쑰인 쑰건을 직접 μ§€μ •ν•˜λŠ” 뢀뢄이 μΆ”κ°€λœ 것을 λ³Ό 수 μžˆλŠ” κ²ƒμ΄μ—μš”. ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό ν•œλ²ˆ μž‘μ„±ν•΄ λ³Όκ²Œμš”!

 

λ°˜μ‘ν˜•

 

 

 

μœ„μ— λ‚΄μš©μ„ μ •λ¦¬ν•΄λ³΄μžλ©΄ μ•„λž˜μ™€ 같은 κ²ƒμ΄μ—μš”.

  1. κ²Œμ‹œλ¬Ό(SystemUseManual) : κ²Œμ‹œλ¬Όμ˜ 번호, 제λͺ©, κ²Œμ‹œλ¬Όμ˜ μž‘μ„± μ‹œκ°„
  2. νšŒμ›(Member) : νšŒμ›μ˜ 이름 / 이메일
  3. λŒ“κΈ€(Comment) : ν•΄λ‹Ή κ²Œμ‹œλ¬Όμ˜ λŒ“κΈ€ 수

 

μœ„μ˜ μ„Έ 개의 μ—”ν‹°ν‹° 쀑에 κ°€μž₯ λ§Žμ€ 데이터λ₯Ό κ°€μ Έμ˜€λŠ” μͺ½μ€ SystemUseManual μ΄λ―€λ‘œ, 이 친ꡬλ₯Ό μ€‘μ‹¬μœΌλ‘œ 쑰인 관계λ₯Ό μž‘μ„±ν•˜λŠ” κ²ƒμ΄μ—μš”. MemberλŠ” SystemUseManual λ‚΄μ— writerλΌλŠ” ν•„λ“œλ‘œ μ—°κ΄€ 관계λ₯Ό λ§Ίκ³  있고, Comment λŠ” μ—°κ΄€ 관계가 μ—†λŠ” 상황인 κ²ƒμ΄μ—μš”. 쑰인 ν›„μ—λŠ” SystemUseManual λ₯Ό κΈ°μ€€μœΌλ‘œ 'GROUP BY' 처리 ν•˜μ—¬ ν•˜λ‚˜μ˜ κ²Œμ‹œλ¬Ό λ‹Ή ν•˜λ‚˜μ˜ 라인이 될 수 μžˆλ„λ‘ 처리(JPQL을 μ΄μš©ν•˜λ©΄ SQL에 μ‚¬μš©ν•˜λŠ” λ§Žμ€ ν•¨μˆ˜ 적용 κ°€λŠ₯)ν•΄μ•Ό ν•˜λŠ” κ²ƒμ΄μ—μš”.

SystemUseManualRepositoryμ—λŠ” Pageable을 맀개 λ³€μˆ˜λ‘œ 전달받고, Page<Object[]> λ°˜ν™˜ νƒ€μž…μ˜ getManualWithCommentCount()λ₯Ό μ•„λž˜μ™€ 같이 μž‘μ„±ν•΄ λ³Ό κ²ƒμ΄μ—μš”.

 

 

 

 

Hibernate: 
    select
        systemusem0_.no as col_0_0_,
        member1_.id as col_1_0_,
        count(systemusem2_.manual_comment_no) as col_2_0_,
        systemusem0_.no as no1_1_0_,
        member1_.id as id1_0_1_,
        systemusem0_.moddate as moddate2_1_0_,
        systemusem0_.regdate as regdate3_1_0_,
        systemusem0_.content as content4_1_0_,
        systemusem0_.title as title5_1_0_,
        systemusem0_.writer_id as writer_i6_1_0_,
        member1_.moddate as moddate2_0_1_,
        member1_.regdate as regdate3_0_1_,
        member1_.email as email4_0_1_,
        member1_.grade as grade5_0_1_,
        member1_.name as name6_0_1_,
        member1_.password as password7_0_1_,
        member1_.phone as phone8_0_1_ 
    from
        system_use_manual systemusem0_ 
    left outer join
        member member1_ 
            on systemusem0_.writer_id=member1_.id 
    left outer join
        system_use_manual_comment systemusem2_ 
            on (
                systemusem2_.manual_no=systemusem0_.no
            ) 
    group by
        systemusem0_.no 
    order by
        systemusem0_.no desc limit ?
Hibernate: 
    select
        count(systemusem0_.no) as col_0_0_ 
    from
        system_use_manual systemusem0_
[com.hongga.junyharang.domain.entity.manual.SystemUseManual@570ede3b, com.hongga.junyharang.domain.entity.member.Member@135f160e, 0]
[com.hongga.junyharang.domain.entity.manual.SystemUseManual@299cddbf, com.hongga.junyharang.domain.entity.member.Member@31beb0d0, 1]

 

1νŽ˜μ΄μ§€μ˜ 데이터λ₯Ό μ²˜λ¦¬ν•œλ‹€κ³  κ°€μ •ν•˜κ³ , νŽ˜μ΄μ§€ λ²ˆν˜ΈλŠ” 0으둜 μ§€μ •ν•˜κ³ , 2개λ₯Ό μ‘°νšŒν•œ κ²ƒμ΄μ—μš”.

 

 

 

μžλ°” ORM ν‘œμ€€ JPA ν”„λ‘œκ·Έλž˜λ°:μŠ€ν”„λ§ 데이터 예제 ν”„λ‘œμ νŠΈλ‘œ λ°°μš°λŠ” μ „μžμ •λΆ€ ν‘œμ€€ 데이터베이

COUPANG

www.coupang.com

"이 ν¬μŠ€νŒ…μ€ 쿠팑 νŒŒνŠΈλ„ˆμŠ€ ν™œλ™μ˜ μΌν™˜μœΌλ‘œ, 이에 λ”°λ₯Έ μΌμ •μ•‘μ˜ 수수료λ₯Ό μ œκ³΅λ°›μŠ΅λ‹ˆλ‹€."

 

 

728x90
λ°˜μ‘ν˜•