티스토리 뷰
컬럼 데이터를 합쳐서 결과값을 보여줘야할 때 쓰는 SQL함수로는 group_concat과 string_agg가 있다.
JPA(queryDsl) 환경에서 어떻게 해당 기능을 쓰는 방법이다.
사실 쿼리는 간단하게 날리고 데이터 전처리는 어플리케이션 단에서 해줘야한다고하지만 당장 어떻게 짜야할지 생각이 안나니 group_concat으로 데이터를 배열 형식으로 받아줬다.
해당 쿼리를
select p.post_id, u.nickname,count(distinct (c.comment_id)) as commentCount ,count(distinct(p2.pick_id)) as likeCount, group_concat(distinct (h.hashtag_name)) as hashtags
from post p
join users u on p.user_id = u.user_id
join post_category_relation pcr on p.post_id = pcr.post_id
left join pick p2 on p.post_id = p2.post_id
left join comment c on p.post_id = c.post_id
left join hashtag h on p.post_id = h.post_id
group by p.post_id
;
이렇게 바꿔주어야하는데
queryFactory.select(new QFeedPost(
p.postId,
u.nickname,
p.content,
c.commentId.countDistinct(),
pp.pickId.countDistinct(),
Expressions.simpleTemplate(String.class, "group_concat({0})", h.hashtagName)))
.from(p)
.where(pcr.categoryCode.in(categoryCode))
.join(u).on(p.user.eq(u))
.join(pcr).on(pcr.post.eq(p))
.leftJoin(pp).on(pp.post.eq(p))
.leftJoin(c).on(c.post.eq(p))
.leftJoin(h).on(h.post.eq(p))
.groupBy(p.postId)
.orderBy(p.createdDate.desc())
.limit(pageable.getPageSize())
.offset(pageable.getOffset())
.fetch();
나머지는 queryDsl에서 제공하는 메서드이지만 group_concat의 기능을 사용할때 해당 기능을 따로 설정해주지 않으면 StringPath에서 해당 메서드를 사용할 수 없다고 뜨기도한다. (혹은 아래 에러가 뜬다)
java.lang.IllegalArgumentException: No pattern found for GROUP_CONCAT
1. 자바 ORM의 경우 어떤 DBMS를 쓰냐에 따라 데이터베이스 유형을 지정할 수 있도록 Dialect설정을 해주는데 이번 예시의 경우 MySQL을 사용했으니 버전에 따라 MySQL5Dialect , MySQL8Dialect를 상속받는 커스텀한 클래스를 작성해주고 group_concat를 사용할 수 있게 등록해준다. (해당 예시는 5지만 본인이 쓰는 SQL버전에 따라 8을 상속하기도 한다)
// org.hibernate.dialect.MySQL5Dialect
public class CustomMysqlDialect extends MySQL5Dialect {
public CustomMysqlDialect() {
super();
// register custom/inner function here
this.registerFunction("group_concat", new SQLFunctionTemplate(StandardBasicTypes.STRING, "group_concat(?1)"));
}
}
2. 그리고 해당 패키지를 인식해서 기존 Dialect말고 자신이 커스텀한 클래스를 빈이 인식할수 있도록 자신이 커스텀한 클래스의 패키지 경로를 작성해준다.
@Configuration
public class JpaConfiguration {
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
AbstractJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(true);
adapter.setDatabase(Database.MYSQL);
// package to CustomMysqlDialect
adapter.setDatabasePlatform("com.xxx.xxx.config.CustomMysqlDialect");
adapter.setGenerateDdl(false);
return adapter;
}
}
3. 쿼리DSL에서 적용됩니다.
// before do this , autowird JPAQueryFactory at first
QReportDoctorTag qReportDoctorTag = QReportDoctorTag.reportDoctorTag;
SimpleTemplate<String> simpleTemplate = Expressions.simpleTemplate(String.class, "group_concat({0})", qReportDoctorTag.tag);
JPAQuery<Tuple> tupleJPAQuery = queryFactory.select(qReportDoctorTag.reportId, simpleTemplate)
.from(qReportDoctorTag)
.groupBy(qReportDoctorTag.reportId);
List<Tuple> fetch = tupleJPAQuery.fetch();
+) 이렇게까지만 하면 해당 값이 List가 아니라 String으로 받아질텐데 나같은 경우 따로 String을 Arry로 매핑해주는 메서드를 따로 짰다. (더 좋은방법이 있을 것 같지만)
private ArrayList<String> stringToArr(String target){
String[] ArraysStr = target.split(" ");
ArrayList<String> result = new ArrayList<String>();
if(target == null){
return null;
}
for (String str: ArraysStr) {
result.add(str);
}
return result;
}
참조한 글들입니다.
1. group_concat 추가
- 참조1: https://www.popit.kr/jpa-querydsl-group_concat-%EC%82%AC%EC%9A%A9%EB%B2%95/
- 참조2: GROUP_CONCAT does NOT work in QueryDSL querydsl/querydsl#2377 -> 사실 이거보고 해결함
2. Pagenation
- 참조1: https://velog.io/@dhk22/Spring-%EC%84%B8%EC%83%81-%EA%B0%84%EB%8B%A8%ED%95%9C-Pagination-Controller%EC%97%90%EC%84%9C-Pageable-%EA%B0%9D%EC%B2%B4-%EB%B0%9B%EC%95%84-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
- 참조2: 종완님이 예시 주셔서 이건 간단하게 해결..
3. queryDsl where절에 IN절 적용 방법
- Total
- Today
- Yesterday
- 실시간클록
- jupyterlab
- 조회수기능
- 목서버
- crudrepository
- 모의서버
- 스마트렌즈
- 해커톤
- 항해해커톤
- mockserver
- 이미지검색
- 데이터잘림
- 항해커톤
- 구글클라우드스토리지
- redis-py
- 주피터랩
- PC시간어떻게
- redisTemplate
- ChatGPT
- 시간어떻게
- visionAPI
- 구글
- redis
- 조회수기능개발
- 빈해쉬맵
- 알고있
- 소숫점잘림
- 실시간클락
- 지도데이터
- 네이버이미지검색
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |