반응형
데이터를 집계해서 뽑아야 할때가 있는데 예를들면 날짜별로 있는 데이터를 월별로 뽑아야 할때 등이다.
예를들어 다음과 같은 테이블과 데이터가 있다고 해보자. 해당 테이블을 월별로 뽑을때 말이다.
쿼리를 만든다면 MYSQL의 경우 DATE_FORMAT을 이용해 만들 수 있는데, 해당 기능은 Mysql에 의존하기 때문에 일반적으로는 불가하다. 그럼에도 호출하려면 Expressions를 이용해 수행할 수 있다.
StringTemplate formattedDate = Expressions.stringTemplate(
"DATE_FORMAT({0}, {1})"
, salesDaily.yyyymmdd
, ConstantImpl.create("%Y-%m"));
Expressions.stringTemplate 기능을 사용해 실행할 수 있는데, 첫번째 인자는 함수명을, 두번째는 컬럼명({0} 에 들어갈 값), 그리고 세번째는 포멧할 유형을 입력했다.
저것을 쿼리 그대로 한다면 다음과 같다.
SELECT
DATE_FORMAT(yyyymmdd, '%Y-%m')
from sales_daily
그래서 위의 format을 SELECT 와 GROUP 안에 넣으면 된다.
데이터를 조회하고 난 뒤 데이터를 저장할 객체를 만든다.
내 경우 QueryProjection을 이용하는데, 의존성이 있긴 하지만 이쪽을 선호하는 편이다.
@Getter
@ToString
public class SalesMonthlyTestDto {
private String yyyymmdd;
private Long cntSum;
private Long salesSum;
@QueryProjection
public SalesMonthlyTestDto(String yyyymmdd, Long cntSum, Long salesSum) {
this.yyyymmdd = yyyymmdd;
this.cntSum = cntSum;
this.salesSum = salesSum;
}
}
이렇게 생성하고 gradle의 compileQuerydsl을 수행하면 Q로 시작하는 객체가 생성된다. 해당 객체를 queryFactory 에 적용해서 다음과 같이 작성했다.
...
public List<SalesMonthlyTestDto> testGroupbyQuery() {
LocalDate startDate = LocalDate.of(2018, 1, 1);
LocalDate endDate = LocalDate.of(2018, 5, 31);
StringTemplate formattedDate = Expressions.stringTemplate(
"DATE_FORMAT({0}, {1})"
, salesDaily.yyyymmdd
, ConstantImpl.create("%Y-%m"));
List<SalesMonthlyTestDto> fetch = queryFactory
.select(
new QSalesMonthlyTestDto(
formattedDate.as("yyyymm")
, salesDaily.cnt.sum()
, salesDaily.sales.sum()
)
)
.from(salesDaily)
.where(salesDaily.yyyymmdd.goe(startDate)
, salesDaily.yyyymmdd.loe(endDate)
)
.groupBy(formattedDate)
.orderBy(formattedDate.asc())
.fetch();
return fetch;
}
...
formattedDate 를 select의 한 부분과 groupBy, orderBy 부분에 적용하여 조회를 한다.
그럼 이제 호출해보는 테스트를 작성한다
@SpringBootTest
class GroupRepositoryTest {
@Autowired
private TestRepository testRepository;
@Test
@DisplayName("그룹 쿼리 실행(querydsl)")
void querydslGroupbyTest() {
List<SalesMonthlyTestDto> salesMonthlyTestDtos = testRepository.testGroupbyQuery();
for (SalesMonthlyTestDto salesMonthlyTestDto : salesMonthlyTestDtos) {
System.out.println("salesMonthlyTestDto = " + salesMonthlyTestDto);
}
}
}
시스템 로그를 보면 다음의 쿼리가 수행된다
SELECT
DATE_FORMAT(salesdaily0_.yyyymmdd, '%Y-%m') AS col_0_0_,
SUM(salesdaily0_.cnt_sum) AS col_1_0_,
SUM(salesdaily0_.sales_sum) AS col_2_0_
FROM
sales_daily_temp salesdaily0_
WHERE
salesdaily0_.yyyymmdd >= '2018-01-01T00:00:00.000+0900'
AND salesdaily0_.yyyymmdd <= '2018-05-31T00:00:00.000+0900'
GROUP BY DATE_FORMAT(salesdaily0_.yyyymmdd, '%Y-%m')
ORDER BY DATE_FORMAT(salesdaily0_.yyyymmdd, '%Y-%m') ASC;
조회 결과 객체에 잘 담겨있는지 확인.
salesMonthlyTestDto = SalesMonthlyTestDto(yyyymmdd=2018-01, cntSum=97061, salesSum=2462960812) salesMonthlyTestDto = SalesMonthlyTestDto(yyyymmdd=2018-02, cntSum=90798, salesSum=2388801767) salesMonthlyTestDto = SalesMonthlyTestDto(yyyymmdd=2018-03, cntSum=111121, salesSum=2804843966) salesMonthlyTestDto = SalesMonthlyTestDto(yyyymmdd=2018-04, cntSum=114052, salesSum=2831963106) salesMonthlyTestDto = SalesMonthlyTestDto(yyyymmdd=2018-05, cntSum=121383, salesSum=3034483299) |
끝.
반응형
'공부 > 프로그래밍' 카테고리의 다른 글
[npm] npm 대신 npx 를 사용하는 이유 (0) | 2020.12.24 |
---|---|
[react + typescript] redux toolkit 사용하기(createAction , ActionType , createReducer) (0) | 2020.12.23 |
[gitlab] root 비밀번호 분실 시 비밀번호 초기화 (0) | 2020.12.16 |
[springboot] @SpringBootTest에서 RestTemplate로 localhost 테스트 시 Connection refused (0) | 2020.12.15 |
[react + next] 구글 애널리틱스 적용하기(gtag) (0) | 2020.12.13 |
댓글