일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 자바JVM
- 속성의 특징
- 고립성
- JAVA JVM
- 복합 속성
- java
- SQL문의 실행 순서
- 제이쿼리text
- 유형과 무형에 따른 엔터티 종류
- 자바스크립트innerText
- 집합 연산
- 자바스크립트경고창
- 관계 연산
- 결합 연산
- Oracle
- 오라클
- 설계 속성
- css 선택자
- SQL 종류
- 파생 속성
- sql
- 다중값 속성
- alert경고창
- 기본 속성
- 속성의 종류
- 테이블의 구조
- 트랜잭션의 특성
- 발생시점에 따른 엔터티의 종류
- 단일 속성
- 연속성
Archives
- Today
- Total
wms's Programming&Study
JPA Querydsl from절에 subquery 사용하기(@Subselect 이용) 본문
이슈사항
이번 내용도 배치로 통계로 구축하다가 생긴 이슈이다.
통계 쿼리를 mybatis로 작성하는 것은 쉬운데 검색해보니
querydsl은 subquery가 select 절이나 where 절에만 사용가능하고
from절에는 불가하다는 내용이 가득해서 통계 쿼리를 작성하는데 골머리 썩었다.
그래도 방법을 찾아서 적어보려고 한다.
해결방안
@Subselect를 이용해서 서브 쿼리로 사용할 엔티티에 일종의 가상 테이블을 만드는 view 처럼 사용하는 것이다.
그렇게 되면 native query로 작성하는 것처럼 사용이 가능하다.
아니면 어플리케이션 레벨에서 처리해야한다.
해결
from 절 조회해오는 데이터의 크기를 줄이는 것이 목적이어서 @Subselect를 사용해서 view처럼 사용하기로 했다.
subquery 엔티티 부분
엔티티 부분을 작성할 때 주의할 점은 select절의 컬럼 이름과 엔티티의 @Column(name = "")
이 부분이 같아야 컬럼을 찾을 수 있으니 주의해야한다.
그리고 이부분의 단점은 where 절에 넣을 수 있는 조건이 동적으로 불가해서 고정적으로
@Entity
@Subselect(
"SELECT " +
"id AS member_id, " +
"TIMESTAMPDIFF(YEAR, birth, CURDATE()) AS age," +
"gender," +
"STR_TO_DATE(created_at, '%Y-%m-%d') AS created_at, " +
"member_status "
"FROM member " +
"WHERE birth IS NOT NULL " +
"AND gender IS NOT NULL"
)
@Immutable
@Synchronize("member")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class AgeGenderSub {
@Column(name = "member_id")
private String memberId;
@Column(name = "age")
private Long age;
@Column(name = "gender")
private String gender;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column
@Enumerated(EnumType.STRING)
private MemberStatus memberStatus;
public AgeGenderSub(String memberId, Long age, String gender, LocalDateTime createdAt, MemberStatus memberStatus) {
this.memberId = memberId;
this.age = age;
this.gender = gender;
this.createdAt = createdAt;
this.memberStatus = memberStatus;
}
}
repository querydsl 부분
아까 생성한 엔티티를 Q테이블로 선언해주고 from 절에 엔티티 부분을 넣어주면 @Subselect 부분에서 조회된 데이터를 사용할 수 있다.
그리고 엔티티에 선언되어 있는 필드를 사용해서 querydsl을 작성할 수 있다.
@Override
public List<AgeGenderDto> findAgeGenderStatistics(
AnalysisKey analysisKey) {
LocalDateTime startDate = analysisKey.getStartDate().atStartOfDay();
LocalDateTime endDate = analysisKey.getEndDate().atStartOfDay();
QAgeGenderSub ageGenderSub = QAgeGenderSub.ageGenderSub;
StringTemplate dateFormat = Expressions.stringTemplate("DATE_FORMAT( {0}, {1} )",
ageGenderSub.createdAt, ConstantImpl.create("%Y-%m-%d"));
StringPath ageType = Expressions.stringPath("age_type");
return queryFactory
.select(
Projections.constructor(AgeGenderDto.class,
dateFormat,
new CaseBuilder()
.when(ageGenderSub.age.lt(10)).then(AgeType.LESS_THAN_10.toString())
.when(ageGenderSub.age.between(11, 19))
.then(AgeType.BETWEEN_11_AND_19.toString())
.when(ageGenderSub.age.between(20, 29))
.then(AgeType.BETWEEN_20_AND_29.toString())
.when(ageGenderSub.age.between(30, 39))
.then(AgeType.BETWEEN_30_AND_39.toString())
.when(ageGenderSub.age.between(40, 49))
.then(AgeType.BETWEEN_40_AND_49.toString())
.when(ageGenderSub.age.between(50, 59))
.then(AgeType.BETWEEN_50_AND_59.toString())
.when(ageGenderSub.age.goe(60)).then(AgeType.GREATER_THAN_60.toString())
.otherwise(AgeType.ETC.toString()).as("age_type"),
ageGenderSub.gender,
ageGenderSub.count()
)
)
.from(ageGenderSub)
.where(
ageGenderSub.isNotNull()
.and(ageGenderSub.createdAt.goe(startDate))
.and(ageGenderSub.createdAt.lt(endDate))
.and(ageGenderSub.memberStatus.eq(MemberStatus.NORMAL))
)
.groupBy(dateFormat, ageType, ageGenderSub.gender)
.fetch();
}
'Programming > JAVA' 카테고리의 다른 글
JPA 엔티티 복합키 설정하기 (0) | 2023.01.08 |
---|---|
나라별 시간대가 필요할 때 LocalDateTime to ZonedDateTime (0) | 2023.01.01 |
프로젝트 어플리케이션 전체 서버 시간 UTC-> KOR로 설정하기 (2) | 2022.12.24 |
동기화, 비동기화, 컨커런트 컬랙션 (0) | 2021.10.16 |
인터페이스와 추상클래스 (0) | 2021.10.10 |