JPA (12) Join, Subquery, Case

김영한님의 자바 ORM 표준 JPA 프로그래밍 강의 정리

JOIN

  • SQL JOIN과 실행하는 것은 동일하지만 엔티티를 중심으로 동작

  • 내부 조인

    • inner 생략 가능
    • SELECT m FROM Member m [INNER] JOIN m.team t
  • 외부 조인

    • outer 생략 가능
    • SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
  • 세타 조인

    • 연관 관계가 없을 때
    • SELECT count(m) FROM Member m, Team t where m.username = t.name
  • ON을 사용한 조인

    • JPA 2.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'
    
    • 연관 관계없는 엔티티 외부 조인 가능(하이버네이트 5.1부터)
    -- 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

  • SQL과 같은 서브 쿼리 가능
-- 서브쿼리에서는 같은 테이블을 새로 정의해서 가져온 경우
-- 성능이 더 좋음
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) : 서브 쿼리 결과 중 하나라도 같은 것이 있으면 참
-- 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)
  • JPA 서브쿼리의 한계
    • WHERE, HAVING 절에서만 서브 쿼리 사용 가능
    • SELECT 절도 가능(하이버네이트에서 지원)
    • FROM 절의 서브 쿼리(inline view) 불가
      • 조인으로 해결할 수 있으면 조인 사용

JPQL 타입 표현

  • 문자: ‘John’, ‘she’’s’
  • 숫자: 10L(long), 10D(double), 10F(float)
  • boolean: TRUE, FALSE
  • enum: sample.enum.SampleEnum.SampleA (패키지 이름 포함)
  • entity: TYPE(m) = member (상속 관계에서 사용)
  • SQL과 문법이 같은 식
    • EXIST, IN
    • AND, OR, NOT
    • =, >, >=, <, <=, <>
    • BETWEEN, LIKE, IS NULL

CASE

  • 기본 case 식
SELECT
	CASE WHEN m.age <= 10 THEN '학생 요금'
			 WHEN m.age >= 60 THEN '경로 요금'
  		 ELSE '일반 요금'
  END
FROM Member m  
  • 단순 case 식
SELECT
	CASE t.score
		WHEN 'A' THEN '인센티브 120%'
		WHEN 'B' THEN '인센티브 110%'
		ELSE '인센티브 105%'
  END
FROM Team t
  • COALESCE : 하나씩 조회해서 null이 아니면 반환
SELECT COALESCE(m.username, '이름 없는 회원') FROM Member m
  • NULLIF : 두 값이 같으면 null 반환, 다르면 첫번째 값 반환
SELECT NULLIF(m.username, '관리자') FROM Member m