간만에 Mysql 삽질 일기
상황은 아래와 같았다.
1. member 테이블 존재 - 학생테이블
2. class 테이블 존재 - 클래스(학반) 테이블
3. class_key 테이블 존재 - 1학생당 여러 클래스에 소속가능하기 때문에 클래스 테이블의 키테이블을 만듬
클라이언트가 원하는 것이 member 페이지에서 학생들을 추출할때 정렬순서를,
클래스 이름 오름차순을 원하는 것이었다.
뭐 한 학생당 클래스가 1개만 존재한다면 아무 문제도 없다. 그냥 member 테이블에 클래스의 고유값을 넣어버리고, 조인을 걸어서 order by 에 적용하면 그만이기 때문이다.
하지만 문제는 한 학생당 여러개의 반을 가질 수 있다는 점이다.
결국 위 3개의 테이블이 모두 조인되어져야 하는 상황이다.
여기서 가장 큰 문제점은 class 테이블과 class_key 테이블은 1:N 의 관계이기 때문에, 조인 쿼리를 날릴 경우,
학생들의 아이디가 중복된 결과가 도출된다는 점이다.
하지만 이 문제는 GROUP BY 절로 묶어버릴 수 있다고 생각했다.
하지만 Mysql 5.7? 이상부터인가 GROUP BY 절의 위 같은 상황은 지원을 해주지 않는다. GROUP BY 는 SUM 이나 COUNT 시에만 사용가능하게 제한을 걸어 버린 것이다.
결국 DISTICT 를 사용하기로 했다.
하지만 역시나 DISTICT 도 문제가 발생했다.
중복이 제거되는 것 까진 좋았는데, LIMIT 문제가 발생했다.
즉 LIMIT 0, 20 을 걸어버리면 이중에 중복 레코드가 만약 2개가 발생한다면 18개의 레코드만 뱉어 버린다.
즉 2개의 레코드가 소실되어 버려서 정확한 레코드 카운터를 토해내지 못하게 된다.
여기서 알아낸 중요한 사실!
쿼리문에서 DISTICT 와 LIMIT 가 같이 있을 경우, 먼저 실행되는 쪽은 LIMIT 이다.
LIMIT 에서 20개를 뽑아낸 다음에 2개를 걸러내 버려서 18개가 나와 버리는 것이다.
만일 DISTICT 가 먼저 실행되었다면 2개를 걸러냈다고 하더라도 20개의 레코드는 나왔을 것이다.(물론 토해내는 레코드가 20개 이상일 것으로 가정한 상황)
결국은 내가 어떻게 해결했냐고?
정말로 사용하기 싫었던......
이것만큼은 쓰기 싫었던......
내가 그토록이나 쿼리에서 가급적이면 사용하지 않는......
서브쿼리!!!
걍 member 쿼리문에 서브쿼리 때려서 서브쿼리 컬럼값으로 ORDER BY 를 때렸다....