쌓고 쌓다

[MySQL] DISTINCT와 ORDER BY 사용시 ORDER BY clause is not in SELECT list 본문

프로그래밍/SQL

[MySQL] DISTINCT와 ORDER BY 사용시 ORDER BY clause is not in SELECT list

승민아 2024. 4. 9. 19:28

원하는기능은 다음과 같았다.

게시글과 댓글은 일대다 관계이고

작성한 댓글의 게시글을 중복없이

최근에 작성한 댓글의 게시글이 먼저 오도록 정렬하는 QueryDSL을 작성하길 원했다.

 

처음에 QueryDSL을 사용하다가 다음과 같은 코드를 작성했었다.

List<PosterResponse> posters = jpaQueryFactory
	.select(new QPosterResponse(
			poster.id,
			poster.writer.id,
			poster.writer.name,
			poster.title,
			poster.content,
			poster.regDate,
			ExpressionUtils.as(
					JPAExpressions
						.select(posterLike.count())
						.from(posterLike)
						.where(posterLike.poster.id.eq(poster.id)), "like_count"),
			ExpressionUtils.as(
					JPAExpressions
						.select(comment.count())
						.from(comment)
						.where(comment.poster.id.eq(poster.id)), "comment_count")
	))
	.from(poster)
	.where(poster.writer.id.eq(memberId))
	.orderBy(poster.regDate.desc())
	.limit(pageable.getPageSize())
	.offset(pageable.getOffset())
	.fetch();

 

실행된 쿼리는 다음과 같고.

select distinct p1_0.id,
		p1_0.member_id,
        w1_0.name,
        p1_0.title,
        p1_0.content,
        p1_0.reg_date,
        (select count(p3_0.id) from poster_like p3_0 where p3_0.poster_id=p1_0.id),
        (select count(c2_0.id) from comment c2_0 where c2_0.poster_id=p1_0.id)
from comment c1_0
left join poster p1_0 on p1_0.id=c1_0.poster_id 
join member w1_0 on w1_0.id=p1_0.member_id where c1_0.member_id=? 
order by c1_0.reg_date desc limit ?,?

 

예외 발생 내용은 다음과 같다.

[Expression #1 of ORDER BY clause is not in SELECT list, references column 'spot.c1_0.reg_date' which is not in SELECT list; this is incompatible with DISTINCT]

 

ORDER BY에 사용된 필드가 SELECT절에 존재하지 않는다는 것이다.

 

MySQL의 쿼리 순서는 다음과 같다.

FROM -> ON -> JOIN -> WHERE -> GROUP BY -> HAVING -> SELECT -> DISTINCT -> ORDER BY

DISTINCT 실행 후에

새로 그려진 테이블에 SELECT 절에 존재하지 않는 필드로 내가 ORDER BY를 실행하려고하니 예외가 발생한 것이다.

 

 

다음 과정을 거쳐 해결했다.

MySQL에서 GROUP BY와 ORDER BY의 실행 순서는

GROUP BY -> ORDER BY 순서이다.

게시글과 댓글을 조인하고

GROUP BY로 게시글의 PK로 묶어준다.

그리고 각 그룹의 댓글이 가장 최신인 순으로 정렬을 한다.

 

작성한 코드는 다음과 같다.

// DISTINCT -> ORDER BY -> OFFSET, LIMIT
// GROUP BY -> ORDER BY -> LIMIT
List<PosterResponse> posters = jpaQueryFactory
    .select(new QPosterResponse(
            poster.id,
            poster.writer.id,
            poster.writer.name,
            poster.title,
            poster.content,
            poster.regDate,
            ExpressionUtils.as(
                    select(posterLike.count())
                    .from(posterLike)
                    .where(posterLike.poster.id.eq(poster.id)), "like_count"),
            ExpressionUtils.as(
                    select(comment.count())
                    .from(comment)
                    .where(comment.poster.id.eq(poster.id)), "comment_count")))
    .from(poster)
    .leftJoin(comment).on(comment.poster.id.eq(poster.id))
    .where(comment.writer.id.eq(memberId))
    .groupBy(poster.id)
    .orderBy(comment.regDate.max().desc())
    .limit(pageable.getPageSize())
    .offset(pageable.getOffset())
    .fetch();
Comments