프로젝트를 진행하면서 생성 날짜 별로 조회해야하는 로직을 작성했어야 했는데 특정 날짜를 조회해야하는데 Entity 요소가 LocalDateTime으로 되어있어서 시간을 제외한 날짜로 조회를 해야했는데 두가지 생각이 들었습니다. LocalDateTime.of(년,월,일,0,0,0) between LocalDateTime(년,월,일,23,59,59)로 처리하는 방법과 뭔가 DATE_FORMAT 함수를 이용할 수 있지 않을까 라는 생각이었습니다. 한번 코드를 통해 알아보겠습니다.
먼저 LocalDateTime으로 처리하는 방식에 대해 알아보겠습니다.
LocalDateTime start = LocalDateTime.of(2023,3,17,0,0,0);
LocalDateTime end = LocalDateTime.of(2023,3,17,23,59,59);
List<Entity> result = queryFactory.selectFrom(entity)
.where(entity.createdDate.between(start,end))
.fetch();
이런식으로 start와 end에 대한 LocalDateTime을 생성하고 between을 통해 조회할 수 있습니다. 하지만 별로 깔끔해 보이지가 않습니다. 년,월,일에 대해 직접 파싱을 해서 넣어줘야하고 번거로운 작업이 늘어나게 됩니다. 그래서 더 좋은 방법이 없을까 생각하게 된게 DATE_FORMAT 함수를 이용하는 것입니다.
익숙한 방식이 아니다보니 좀 많이 헤맸던 것 같습니다. 그래서 어떻게 하냐면 StringExpression을 이용하는 것입니다. StringExpression은 말그대로 문자열 표현식 입니다. 이걸 어떻게 활용하는지 코드로 확인해보도록 하겠습니다.
String date = "2023-03-17"
StringExpression formattedDate = Expressions.stringTemplate("FUNCTION('DATE_FORMAT', {0}, '%Y-%m-%d')", entity.createdDate);
List<Entity> result = queryFactory.selectFrom(entity)
.where(formattedDate.eq(date))
.fetch();
먼저 FUNCTION이라는 처음보는 친구가 있는데 이것은 QueryDSL에서 제공하는 문자열 함수를 호출하기 위한 표현식 입니다. FUNCTION('함수명', 인수1, 인수2) 이렇게 사용 가능합니다. 그래서 DATE_FORMAT이라는 함수를 사용하기 위해 위와같이 선언하였습니다. 인수로는 createdDate를 넘겨주고 equal로 date와 같은지 비교해주게 됩니다. LocalDateTime보다 엄청 간결해진걸 알 수 있습니다. 하지만 주의할 점이 데이터베이스 마다 함수가 다르기 때문에 Mysql상에서는 DATE_FORMAT을 사용하고 H2상에서는 FORMATDATE를 사용합니다. 그래서 데이터베이스 방언마다 다르게 처리 해줘야 한다는 것을 인지하고 개발하도록 합시다.