티스토리 뷰

이전 포스팅에서 한 테이블 내에서 특정 값을 그룹핑하여 최댓값을 가진 row를 가진 방법을 보았었다.

이때 Row_Number를 사용하여 추출한 데이터가 가장 빠른 방법으로 보였는데, 이는 서브 쿼리로 해야 한다는 점이 있다.

 

하지만..

JPQL?hibernate?에 의해 where절과 select절에서만 서브 쿼리가 사용 가능하다고 한다..(내부적인 원리는 나중에 따로 공부해봐야겠다.)

참고 글 : https://stackoverflow.com/questions/60258377/querydsl-4-x-subqueries-in-the-from-clause

 

QueryDSL 4.x subqueries in the FROM clause

Are subqueries in the from clause supported in the latest QueryDSL version? I tried my best but could not find a solution for now.

stackoverflow.com

 

ㅇㅏ무튼... 어떻게든 querydsl에서 서브 쿼리를 사용해서 위 케이스를 풀어낼 수 없을까 생각하다가.. 엔티티 레벨(?)에서 설정할 수 있는 법이 없을까 고민하다가 우연히 봤었던 @SubSelect 옵션이 생각났다.

참고 글 : https://stackoverflow.com/questions/25226244/what-is-the-use-of-synchronize-in-hibernate

 

What is the use of @Synchronize in Hibernate

As per Hibernate documentaion, There is no difference between a view and a base table for a Hibernate mapping. This is transparent at the database level, although some DBMS do not support vi...

stackoverflow.com

 

마치 view처럼 사용할 수 있는 entity를 만드는 걸로 entity에 맵핑할 쿼리를 직접 작성하는 것이다.

 

/**
 * Map an immutable and read-only entity to a given SQL select expression.
 *
 * @see Synchronize
 *
 * @author Sharath Reddy
 */
@Target(TYPE)
@Retention(RUNTIME)
public @interface Subselect {
	/**
	 * The query.
	 */
	String value();
}

주석의 내용과 같이 update될 수 없는 select용 엔티티이다.

 

@Entity
@Subselect(
    "select " +
    "       ROW_NUMBER() over (PARTITION BY c.User_Seq ORDER BY Apply_Date desc, Config_Seq desc) as Row_Num, " +
    "       c.Config_Seq, " +
    "       c.User_Seq, " +
    "       c.Apply_Date " +
    "from CONFIG c "
)
@Immutable
@Synchronize("CONFIG")
public class ConfigSubSelect {

    @Column(name = "Row_Num")
    private Long rowNum;

    @Id
    @GeneratedValue
    @Column(name = "Config_Seq")
    private Long configSeq;

    @Column(name = "User_Seq")
    private Long userSeq;

    @Column(name = "Apply_Date")
    private LocalDate applyDate;

}

 

이렇게 되면 테이블 단위가 아닌 subselect에 작성된 query로 결과가 엔티티에 맵핑되게 된다.

그리고 이 엔티티를 똑같이 querydsl에서 사용해보자.

query
	.selectFrom(configSubSelect)
	.where(configSubSelect.rowNum.eq(1L))
	.fetch();

select configsubs0_.Config_Seq as config_s1_0_,
       configsubs0_.Apply_Date as apply_da2_0_,
       configsubs0_.Row_Num    as row_num3_0_,
       configsubs0_.User_Seq   as user_seq4_0_
from (select ROW_NUMBER() over (PARTITION BY c.User_Seq ORDER BY Apply_Date desc, Config_Seq desc) as Row_Num,
             c.Config_Seq,
             c.User_Seq,
             c.Apply_Date
      from CONFIG c) configsubs0_
where configsubs0_.Row_Num = ?

실행결과의 query를 보면 서브 쿼리로 원하는 서브 쿼리가 나간 것을 확인할 수 있다.

querydsl은 jpql기반이기 때문에, JPQL 마찬가지로 동작될 것으로 예상되고, spring data jpa에서 제공하는 find~ 메서드 또한 동일하게 사용 가능하다.

물론, update나 insert는 불가능하고, 엔티티 파일을 하나 더 만들어야 하지만,

비즈니스적으로 서브 쿼리를 써야만 하는 테이블이라면 다른 곳에서도 똑같이 쓸 확률이 있기 때문에 만들어놓고 공통으로 사용해도 괜찮을 것 같다

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함