inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

실전! Querydsl

스프링 데이터 페이징 활용3 - 컨트롤러 개발

querydsl orderspecifier 조건 분기

해결된 질문

886

olive3three

작성한 질문수 6

0

private List<OrderSpecifier> getOrderSpecifier() {

        List<OrderSpecifier> orderSpecifiers = new ArrayList<>();

        //승인 안된 관리자 우선 조회
        orderSpecifiers.add(new OrderSpecifier<>(Order.ASC, admin.isAuthorized));

        orderSpecifiers.add(new OrderSpecifier(
                new CaseBuilder()
                        .when(admin.isAuthorized.eq("FALSE")).then(admin.createdAt.asc()) 
                        .when(admin.isAuthorized.eq("TRUE")).then(admin.createdAt.desc()) 
        ));

        return orderSpecifiers;
    }

아래와 같은 order 순서로 정렬하려 하는데 2,3 조건을 나누는 부분이 잘 되지 않아 질문 남깁니다. CaseBuilder 대신 다른 방법이 있나요?

  1. 승인 받지 못한 관리자(isAuthorized = 'FALSE') 먼저 조회

  2. isAuthorized = 'FALSE' 인 경우에는 createdAt asc

  3. isAuthorized = 'TRUE' 인 경우에는 createdAt desc

java jpa

답변 3

0

김영한

안녕하세요. olive3three님

우선 case 쿼리를 작성할 때 항상 else 조건을 생각해야 합니다.

현재 else 조건을 넣지 않았는데요. 이 경우 조건을 만족하지 않으면 숫자는 0, 나머지는 null이 됩니다.

참고로 Querydsl에서는 otherwise()를 넣어주어야 합니다.

 

2가지 정도 해결 방안을 말씀드릴게요.

먼저 적어주신 내용으로는 다음과 같이 쿼리를 작성하시면 됩니다.

List<Admin> result = queryFactory.selectFrom(admin)
        .orderBy(new CaseBuilder()
                        .when(admin.isAuthorized.eq("FALSE")).then(0)
                        .when(admin.isAuthorized.eq("TRUE")).then(1)
                        .otherwise(2).asc(),
                new CaseBuilder()
                        .when(admin.isAuthorized.eq("FALSE")).then(admin.createdAt)
                        .otherwise(LocalDateTime.now()).asc(),
                new CaseBuilder()
                        .when(admin.isAuthorized.eq("TRUE")).then(admin.createdAt)
                        .otherwise(LocalDateTime.now()).desc()
        )
        .fetch();

 

다음과 같이 날짜 자체를 숫자로 변경한 다음, 숫자로 변경한 날짜를 정렬 조건으로 사용해 한번에 처리하는 방식으로 문제를 해결할 수도 있습니다.

// 날짜를 문자로 변경한 다음에 문자를 양수로 변경
StringTemplate formattedDateAsc = Expressions.stringTemplate(
        "CAST(FORMATDATETIME({0}, {1}) AS LONG)"
        , admin.createdAt
        , ConstantImpl.create("yyyyMMddHHmmss")); // 양수

// 날짜를 문자로 변경한 다음에 문자를 음수로 변경
StringTemplate formattedDateDesc = Expressions.stringTemplate(
        "CAST(FORMATDATETIME({0}, {1}) AS LONG)"
        , admin.createdAt
        , ConstantImpl.create("-yyyyMMddHHmmss")); // 음수

List<Admin> result = queryFactory.selectFrom(admin)
        .orderBy(new CaseBuilder()
                .when(admin.isAuthorized.eq("FALSE")).then(formattedDateDesc)
                .when(admin.isAuthorized.eq("TRUE")).then(formattedDateAsc)
                .otherwise(formattedDateAsc).asc())
        .fetch();

감사합니다.

 

1

olive3three

답변 감사합니다!!

0

David

안녕하세요. olive3three님, 공식 서포터즈 David입니다.

나누는 부분이 어떻게 잘 안되는지 조금 더 구체적으로 질문을 남겨주실 수 있으실까요?🙂

감사합니다.

0

olive3three

image

IS_AUTHORIZED = 'FALSE'인 경우에는 CREATED_AT이 내림차순으로 IS_AUTHORIZED = 'TRUE'인 경우에는 CREATED_AT이 오름차순으로 정렬되었으면 합니다.

0

김영한

안녕하세요. olive3three님

정확히 어떤 문제인지 저희가 이해하기 위해서 추가 정보가 필요합니다. 먼저 기대하는 내용이 SQL에서 작동하는지 확인이 필요합니다.
다음 내용을 자세히 남겨주세요 🙂

  1. 테이블 DDL

  2. 예제 insert DML

  3. 생각하시는 조회 SQL

  4. SQL 실행의 조회 결과

감사합니다.

0

olive3three

  1. Admin 테이블 DDL
    DROP TABLE IF EXISTS ADMIN CASCADE; CREATE TABLE ADMIN ( ADMIN_ID BIGINT UNSIGNED GENERATED BY DEFAULT AS IDENTITY, LOGIN_ID VARCHAR(20) NOT NULL, PASSWORD VARCHAR(100) NOT NULL, NAME VARCHAR(5) NOT NULL, EMAIL VARCHAR(45) NOT NULL, IS_AUTHORIZED VARCHAR(10) NOT NULL, AUTHORITY VARCHAR(15) NOT NULL, CREATED_AT TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, MODIFIED_AT TIMESTAMP, PRIMARY KEY (ADMIN_ID), UNIQUE KEY ADMIN_LOGIN_ID_UNIQUE (LOGIN_ID), UNIQUE KEY ADMIN_EMAIL_UNIQUE (EMAIL) );

  2. 예제 insert DML

INSERT INTO TEST VALUES(1, 'admin1', 'admin1234!', '관리자1', 'admin1@gmail.com', 'TRUE', 'ROLE_ADMIN', '2024-07-11 14:30:00', '2024-07-11 14:30:00');

INSERT INTO TEST VALUES(2, 'admin2', 'admin1234!', '관리자2', 'admin2@gmail.com', 'TRUE', 'ROLE_ADMIN', '2024-07-12 14:30:00', '2024-07-12 14:30:00');

INSERT INTO TEST VALUES(3, 'admin3', 'admin1234!', '관리자3', 'admin3@gmail.com', 'FALSE', 'ROLE_ANONYMOUS', '2024-07-13 14:30:00', '2024-07-13 14:30:00');

INSERT INTO TEST VALUES(4, 'admin4', 'admin1234!', '관리자4', 'admin4@gmail.com', 'FALSE', 'ROLE_ANONYMOUS', '2024-07-14 14:30:00', '2024-07-14 14:30:00');

  1. 조회 SQL

SELECT * FROM TEST

ORDER BY

CASE

WHEN is_authorized = 'FALSE' THEN 0

WHEN is_authorized = 'TRUE' THEN 1

END,

CASE

WHEN is_authorized = 'FALSE' THEN created_at

END ASC,

CASE

WHEN is_authorized = 'TRUE' THEN created_at

END DESC;

  1. SQL 실행의 조회 결과

image
3번의 SQL문을 QueryDsl로 바꾸고 싶습니다. 또한 SQL문이 올바르게 짠건지 궁금합니다.

0

김영한

본문에 추가로 답글 달아두었습니다 :)

0

인프런 AI 인턴

안녕하세요, 인프런 AI 인턴입니다. olive3three님의 질문과 관련해, 주어진 조건에 따라 특정 엔티티의 리스트를 정렬하는 방법에 대해 질문하셨군요. 여러분이 질문하신 OrderSpecifier를 사용하여 isAuthorized의 값에 따라 다른 정렬 순서를 적용하는 방법에 대해 말씀드리겠습니다.

질문하신 내용과 유사한 상황에 대해 처리하는 방법을 설명한 기존 답변은 아래 링크에서 찾을 수 있습니다:

  • “정렬 조건에 대해 질문이 있습니다.”에서는 enum 값을 기준으로 커스텀 정렬을 해야 할 때 CaseBuilder를 사용하는 방법을 설명하고 있습니다. 여러분의 경우에도 CaseBuilder를 이용하여 isAuthorized 값에 따라 다른 정렬 기준을 적용하는 것이 가능합니다. 이 방법은 여러분이 사용하고자 하는 조건 분기에 맞게 조금만 변형하면 적용할 수 있을 것으로 보입니다.

위의 답변에서 CaseBuilder를 사용하여 조건에 따라 다른 OrderSpecifier를 생성하는 방식을 다루고 있으며, 이 방법은 여러분이 시도하고자 하는 조건 분기에 맞게 적응할 수 있습니다. 주어진 코드 예제에서는 enum 값을 기준으로 정렬 순서를 정의하는 예를 다루었으나, 해당 방식을 isAuthorized 값에 기반하여 수정하는 것도 가능합니다. 예를 들면, isAuthorized 값에 따라 다른 createdAt 정렬 순서를 적용하려면, 여러분의 CaseBuilder 로직을 유지하면서, 적절한 반환 타입을 활용해야 합니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

SpringBoot 4.X에서의 Querydsl 설정

0

122

2

querydsl 오픈소스에 대한 질문

1

88

1

예제에서의 카운트 쿼리에서 join문과 where문은 필요없지 않나요?

0

118

1

Querydsl 6.X버전에 대해서 어떻게 생각하시나요?

0

336

2

여러 테이블 조인하여 통계치를 구하고자 할 때 어떤 방법이 더 효율적일까요

1

78

1

fetchResults()는 더이상 권장되지 않는다는데 맞나요?

0

168

1

querydsl sum() 메서드 없어요.

0

165

2

build 디렉터리 생성

0

147

2

자바 ORM 표준 JPA 프로그래밍 - 기본편 듣고 바로 학습해도 괜찮을까요?

0

119

2

현재 Querydsl에서 from절 서브쿼리를 지원하나요?

0

98

1

오타 제보 드립니다.

0

76

2

벌크 연산과 flush, clear

0

81

1

Run As Intellij 로 변경시 Q타입 import 불가

0

93

1

QHello import하기 문제 발생

0

152

2

등록된 함수 보는법(H2Dialect) 질문

0

73

2

5.0부터 Querydsl은 향후 fetchCount() , fetchResult() 를 지원하지 않기로 결정했다고 하는데 이에 맞는 강의

1

203

2

[환경설정 PDF 부트 3.0이후 설명 질문] build.gradle에 compileQuerydsl을 정의하지 않은 상태에서 Gradle->Tasks->other->compileQuerydsl을 클릭하라고 하는 이유가 무엇인가요??

1

207

1

querydsl 설정 문제

0

225

2

quey dsl 설정부분

0

161

2

count 쿼리 관련 질문입니다!

0

77

1

stringtemplate를 이용하여 where절 검색 방법 질문 드립니다.

0

92

1

답변부탁드리겠습니다.

0

92

2

(OrderSpecifier)관련 내용 어디있을가요

0

67

1

중급문법 벌크연산에서

0

84

2