QueryDSL 기본 문법 - 3

서브 쿼리

JPAExpressions를 사용하면 된다.

@Test
void subQuery() {
    QMember memberSub = new QMember("memberSub");
    List<Member> result = query
                          .selectFrom(member)
                          .where(member.age.eq(
                                  JPAExpressions
                                          .select(memberSub.age.max())
                                          .from(memberSub)
                          ))
                          .fetch();
    assertThat(result).extracting("age").containsExactly(40);
}

나이가 가장 많은 회원을 조회한다.

서브 쿼리는 alias가 겹치면 안 되기 때문에 Q 타입을 하나 추가로 생성해준다.

@Test
void subQueryGoe() {
    QMember memberSub = new QMember("memberSub");
    List<Member> result = query
                          .selectFrom(member)
                          .where(member.age.goe(
                                  JPAExpressions
                                          .select(memberSub.age.avg())
                                          .from(memberSub)
                          ))
                          .fetch();
    assertThat(result).extracting("age").containsExactly(30,40);
}

나이가 평균 이상(goe, >=)인 회원을 조회한다.

@Test
void subQueryIn() {
    QMember memberSub = new QMember("memberSub");
    List<Member> result = query
                          .selectFrom(member)
                          .where(member.age.in(
                                  JPAExpressions
                                          .select(memberSub.age)
                                          .from(memberSub)
                                          .where(memberSub.age.gt(10))
                          ))
                          .fetch();
    assertThat(result).extracting("age").containsExactly(20, 30, 40);
}

in절도 가능하다. 10살 초과(gt, >)인 회원을 조회한다.

@Test
void selectSubQuery() {
    QMember memberSub = new QMember("memberSub");
    List<Tuple> result = query
                         .select(member.username,
                                 JPAExpressions
                                         .select(memberSub.age.avg())
                                         .from(memberSub))
                         .from(member)
                         .fetch();
}

select절에 서브 쿼리도 가능하다. 모든 회원의 이름하고 평균 나이가 조회된다.

JPAExpressionsstatic import 가능하다.

CASE 문

단순한 조건

List<String> result = query
                      .select(member.age
                              .when(10).then("열살")
                              .when(20).then("스무살")
                              .otherwise("기타"))
                      .from(member)
                      .fetch();

복잡한 조건

List<String> result = query
                      .select(new CaseBuilder()
                              .when(member.age.between(0, 20)).then("0~20살")
                              .when(member.age.between(21, 30)).then("21~30살")
                              .otherwise("기타"))
                      .from(member)
                      .fetch();

QueryDSL은 자바 코드로 작성하기 때문에 다음처럼도 가능하다.

@Test
void rankPath() {
    NumberExpression<Integer> rankPath = new CaseBuilder()
            .when(member.age.between(0, 20)).then(2)
            .when(member.age.between(21, 30)).then(1)
            .otherwise(3);
    
    List<Tuple> result = query
            .select(member.username, member.age, rankPath)
            .from(member)
            .orderBy(rankPath.desc())
            .fetch();
    
    for (Tuple tuple : result) {
        String username = tuple.get(member.username);
        Integer age = tuple.get(member.age);
        Integer rank = tuple.get(rankPath);
        System.out.println("username = " + username + ", age = " + age + ", rank = " + rank);
    }
}

rankPath에 복잡한 조건을 변수로 선언해서 select절, orderBy절에서 함께 사용했다.

0-30살이 아닌 회원을 가장 먼저 출력하고, 다음에 0-20살, 다음에 21~30살을 출력한다.

//실행 결과
username = member4, age = 40, rank = 3
username = member1, age = 10, rank = 2
username = member2, age = 20, rank = 2
username = member3, age = 30, rank = 1

상수, 문자 더하기

Expressions.constant()를 사용한다.

List<Tuple> result = query
                     .select(member.username, Expressions.constant("A"))
                     .from(member)
                     .fetch();
//실행 결과
[member1, A]
[member2, A]
[member3, A]
[member4, A]

이름과 문자를 함께 출력한다.

List<String> result = query
                      .select(member.username.concat("_").concat(member.age.stringValue()))
                      .from(member)
                      .where(member.username.eq("member1"))
                      .fetch();
//실행 결과
member1_10

이름 + - + 나이를 출력한다.

member.age.stringValue() : 문자가 아닌 다른 타입들은 StringValue()로 문자로 변환할 수 있다. ENUM을 처리할 때 유용하다.

Last updated