Dev Framework/Spring

[Spring][JPA] Hibernate에서 FROM 절 서브쿼리를 만들 수 없는 이유

개발자 성현 2025. 4. 28. 14:09

Hibernate에서 FROM 절 서브쿼리를 만들 수 없는 이유

"어? SQL에서는 FROM 절 안에 서브쿼리를 넣을 수 있는데, Hibernate는 왜 안 될까?"

JPA를 처음 배우다 보면 누구나 한 번쯤 이런 의문을 품게 됩니다.

오늘은 이 질문을 정확하게, 그리고 실전 관점에서 풀어보겠습니다.

 

JPA와 Hibernate, 그리고 JPQL

우선 출발점부터 바로잡아야 합니다.

Hibernate는 JPA의 대표적인 구현체입니다.

그리고 JPA에서는 데이터베이스를 직접 다루지 않고,

JPQL이라는 "객체지향 쿼리 언어"를 사용합니다.

  • SQL은 테이블을 대상으로 쿼리합니다.
  • JPQL은 엔티티 객체를 대상으로 쿼리합니다.

이게 둘의 본질적인 차이입니다.

 

JPQL은 FROM 절 서브쿼리를 허용하지 않는다

문제는 여기서 발생합니다.

JPQL은 설계 철학상,

"객체(Entity)"를 중심으로 쿼리를 작성해야 한다는 원칙을 가지고 있습니다.

따라서

SELECT m FROM (SELECT m FROM Member m WHERE m.age > 20) m

같은 형태,

FROM 절에 또 다른 SELECT 쿼리를 넣는 것을 지원하지 않습니다.

 

이유는 간단합니다:

JPQL의 FROM 절에는 반드시 "엔티티"만 등장해야 한다는 규칙이 있기 때문입니다.

JPQL은 "객체 간 탐색"에 초점을 맞췄지,

"임시 테이블"을 만드는 SQL 스타일 서브쿼리는 고려하지 않았습니다.

 

Hibernate는 표준을 따른다

Hibernate는 JPA를 구현할 때,

JPQL 표준 스펙을 그대로 따릅니다.

  • JPQL이 허용하는 것만 Hibernate도 허용합니다.
  • JPQL이 막아놓은 건 Hibernate도 막을 수밖에 없습니다.

결국 Hibernate가 FROM 절 서브쿼리를 막는 이유는,

Hibernate 자체의 한계가 아니라, JPA 스펙(JPQL) 자체의 제한입니다.

 

그렇다면 복잡한 쿼리는 어떻게 해야 할까?

실전에서는 FROM 절에 서브쿼리가 필요한 경우가 분명 존재합니다.

예를 들어,

  • 통계 데이터
  • 집계 결과를 다시 조인하는 경우
  • 복잡한 필터링이 필요한 경우 등

이럴 때 실무에서는 보통 이렇게 해결합니다:

방법 설명

쿼리를 2단계로 나눈다 1차 조회 → 결과값으로 다시 조회
조인으로 대체 가능하면 서브쿼리 대신 조인 활용
Native Query 사용 직접 SQL 작성해서 사용하는 방법
QueryDSL 활용 복잡한 조건을 코드 조립 방식으로 작성 (단 FROM 서브쿼리는 불가)

 

가장 간단한 방법은 Native Query를 쓰는 것입니다.

Spring Data JPA에서는 이렇게 작성할 수 있습니다:

@Query(value = "SELECT * FROM (SELECT * FROM member WHERE age > 20) m", nativeQuery = true)
List<Member> findMembersUsingSubquery();

물론 Native Query는 타입 안전성이 없고, 유지보수 비용이 올라가기 때문에 신중하게 써야 합니다.

 

요약

  • Hibernate가 FROM 절 서브쿼리를 못 쓰는 건 Hibernate 한계가 아니다.
  • JPQL(그리고 JPA 스펙) 자체가 FROM 절 서브쿼리를 막아두었기 때문이다.
  • 복잡한 쿼리가 필요하면 쿼리 분리, 조인 대체, Native Query 등을 활용해야 한다.

 

✨ 마무리: Hibernate를 오해하지 말자

Hibernate는 단순히 표준을 따르고 있을 뿐입니다.

오히려 Hibernate는 JPQL을 SQL로 번역할 때 정말 많은 최적화를 수행합니다.

진짜 원인은 Hibernate가 아니라,

"JPQL은 객체 모델 탐색을 최우선으로 설계되었다"는 점을 이해하면 이 의문은 자연스럽게 풀립니다.

 

🔥 한줄로 정리

"Hibernate는 FROM 절 서브쿼리를 막은 게 아니라, JPA 표준(JPQL)이 그것을 막았을 뿐이다."