이번주 코테가 여러개 있어.. SQL 공부를 다시 하고 있다. 

그 김에 팀프로젝트에서 알게 되었던 내용에 대해 다시 정리해 보았다. 

🔧 SELECT DISTINCT 와 ORDER BY 가 함께 쓰이는 경우 정렬은 예상하지 못하게 일어난다

팀프로젝트를 하는데, 팀원 분의 쿼리에서 예상했던 결과가 나오지 않고 있었다.
나 역시 해당 쿼리로 해결 할 수 있을 거라 생각했는데 원하는 결과가 나오지 않았고, 이를 해결하는 과정에서 SELECT DISTINCT 와 ORDER BY 가 함께 쓰는 경우, 주의해야 함을 알게 되었다.

 

🔧 당시 상황

study - book 은 다대일 관계 ( study -> book 으로 book 의 pk 를 참조하고 있다 )

쿼리로 가져오려고 한 것 : 최근에 스터디가 생성된 책 목록을 가져오기

 

먼저, Study 테이블에 들어있는 데이터를 살펴보자. 

최근에 스터디가 생성된 책 목록을 뽑아내고 싶다면 ( 당연히 , 이 책 목록역시 최신 생성 스터디 순으로 + 당연히 책은 중복 없이 ) 

 

위의 상태에서는 다음 id 순으로 book 이 출력될 것을 기대했다

2

1

4

3

 

 

그래서 이와 같은 쿼리를 작성했다

SELECT DISTINCT book.*
FROM book 
INNER JOIN study on book.id = study.book_id
ORDER BY study.created_at DESC;

 

하지만 이 결과 출력되는 책의 순서는 2,1,3,4 였다

 

 

어떻게 이런 일이 발생한 걸까?

 

🔧주의 해야 하는 상황 : (MySQL) 

MySQL 에서는 아래와 같이 “DISTINCT 키워드 가 붙은 컬럼”“ORDER BY 의 기준이 되는 컬럼” 이 서로 다른 경우 주의해야 한다. 

SELECT DISTINCT(col_1), ....
...
ORDER BY col_2 DESC 
..;

MySQL 의 경우 위와 같은 상황이 "허용"되기에 주의해야 한다! 

 

다른 DB 들에서는 이런식으로 order by 컬럼과, distinct 컬럼이 서로 다른 경우, 예외를 발생시킨다고 한다.

근데 mysql 에서는 그냥 실행시켜주고.. 이거 결과가 왜이래? 하게 되는 것 같다.

 

 

🔧 어떤 일이 발생하나? 

이는 위의 쿼리가 처리 되는 "순서"에 의해 발생하는 상황이다. 

 

- 우리의 기대: ORDER BY 가 먼저 일어나고 ->이렇게 정렬된 Study 와 book 을 join 한 결과에서 distinct 한 튜플들로 생성된 릴레이션이 나올 것

  • 하지만, 실제로는 그냥 원본 테이블 상에서 가장 먼저 등장한 튜플을 DISTINCT 로 뽑아 낸 이후ORDER BY 를 하기 때문이다.
    • 따라서, 우리가 원하는 튜플(레코드)이 뒤쪽에 등장했다면, 중복 제거된 상태로 추출한 데이터를 정렬하기에, 원하는 결과를 얻지 못하게 되는 것이었다.

 

복사했습니다!