본문 바로가기

Spring Boot/Spring Data JPA

queryDsl) subquery limit 1

시작하기 전 아쉽게도 (querydsl) 서브쿼리에서 limit 옵션은 동작하지 않는다

정확한 이유는 잘 모르겠지만 쿼리가 실행될때 JPQLSerializer를 사용하여 싱글쿼리 문자열이 빌드된다.

이 과정에서 sub query limit가 적용되지 않는 것 같다 (jpql는 limit 옵션을 지원하지 않는다)

 

그렇다면 서브쿼리에서 limit처럼 동작하게 하는법은 무엇이 있을까?

아래와 같은 예제가 있다.

(App 과 Version 은 일대 다 관계이다)

// 부모
@Entity
public class App {

    @Id
    @Column(name = "APP_NUM", nullable = false)
    private Long Id;
    
    @Column(name = "APP_NM")
    private String appName;

    @OneToMany(mappedBy = "app", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<Version> versions;
}

 

// 자식
@Entity
public class Version {

    @Id
    @Column(name = "VER_NUM", nullable = false)
    private Long id;
    
    @Column(name = "VER_NM", nullable = false, length = 100)
    private String versionName;
    
    @Column(name = "LINK", nullable = false)
    private String link;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "APP_ID")
    private App app;
}

 

위 관계에서 query Dsl을 사용하여 모든 앱 이름과 앱에 대한 최신 버전 정보  같이 보여주고싶다.

sub query에 order by 와 limit 를 대신하여 sub query max를 사용한다.

 

서브쿼리로 해당 버전의 가장 높은 아이디를 가져와서 조건에 넣는 방법이다.

전체 리스트에 버전과 버전 정보를 모두 가져와야 하므로 join 조건에 서브쿼리를 사용하여 최신정보를 가져온다.

(만약 id나 버전 이름만 가져올때는 select subqeury를 사용해도 된다)

// query dsl
return jpaQueryFactory.select(
        new QAppResponse(
                app,
                appName,
                version.id,
                version.versionName,
                version.link
		)
        )
        .from(app)
        .leftJoin(version)
            .on(version.id.eq(
                            JPAExpressions.select(version_2.id.max())
                                    .from(version_2)
                                    .where(version_2.app.id.eq(app.id))
                    )
            )
...

 

-- SQL
select
	t1_0.APP_NUM,
        t1_0.APP_NM,
        t2_0.VER_NUM,
        t2_0.VER_NM,
        t2_0.LINK
from
        APP t1_0 
left join
        APP_VER t2_0 
            on t2_0.VER_NUM=(
                select
                    max(t3_0.SW_RELS_NUM) 
                from
                    APP_VER t3_0 
                where
                    t3_0.APP_NUM=t1_0.APP_NUM
        )

 

단 이 방법은 고유한 아이디의 max값을 가져오는 것이라 중복되는 값에 max() 를 사용할때는 조건을 더 추가해야한다.

'Spring Boot > Spring Data JPA' 카테고리의 다른 글

querydsl 에서 case문 사용하기  (0) 2024.01.07
QueryDsl) BooleanExpression  (1) 2023.12.17
queryDsl 정리 및 예제  (1) 2023.12.03
JPA) JPA Auditing으로 자동화  (0) 2023.12.01
QueryDSL) From 절 SubQuery를 쓰고싶어  (2) 2023.11.23