갑자기 잘 작동하던 프로시저가 sql_mode 활성화 후 error가 났다.
찾아보니까 Group by가 문제라고 하는데
잘 되던 프로시저가 왜....???? 라는 의문이 들어 이슈를 해결하다가
같은 이슈를 직면한 분들에게 도움이 될까 포스팅해보았다.
결론부터 보고 싶으신 분들은 GROUP BY 개념은 패스하세요:)
조건에 따라 그룹화하여 집계를 내거나(GROUP BY), 그룹화 내에 특정 조건으로 추출하고 싶을 때 (HAVING)사용
ex) 각 학년별 총 학생수를 구하고 싶다.
SELECT
COUNT(학생고유번호)
FROM 학교
GROUP BY 학년
ex) 각 학년별 총 학생수를 구하고 싶다 (단, 3학년 미만 학년만 조회)
SELECT
COUNT(학생고유번호)
FROM 학교
GROUP BY 학년
HAVING 학년 < 3
MySQL(v5.7 이후) 버전업되면서 SQL 문법이 이전보다 엄격해졌다.
회사에서 sql_mode를 안켜고 작업을 하다가
최근들어 SQL 모드를 킨 DB서버가 생겼고, 그 후 당연하게 쓰면서 잘못 된 걸 몰랐던 이슈들이 빠방 터졌다.
그 중 아래와 같은 ERROR를 내뱉는 쿼리가 있었다.
Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column '컬럼명' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
마지막 문장을 보면
'this is incompatible with sql_mode=only_full_group_by'
sql_mode 중 only_full_group_by에 맞지 않는 쿼리라고 한다.
[공식 문서 정의]
해당 옵션이 활성화되어있을 경우
MySQL은 선택 목록, 조건 또는 목록이 절에 명명되지 않았거나 기능적으로 종속되지 않은 비집계 열을 참조하는 쿼리 를 HAVING거부한다.
즉, mysql이 지정한 group by 표준 규칙에 맞게 쿼리를 수정하라는 뜻이다.
해당 에러를 해결하기 위해서는 두가지의 해결 방법이 있다.
SELECT
o.custid
, c.name
, MAX(o.payment)
FROM orders AS o, customers AS c
WHERE o.custid = c.custid
GROUP BY o.custid;
위 예시는 GROUP BY
로 o.custid
를 그룹화하여 SELECT하는 쿼리이다.
이렇게 작성하면 위의 에러가 나올 것이다.
GROUP BY
를 사용할 경우, SELECT
할 수 있는 컬럼은
GROUP BY
에 나열된 컬럼 (여기서는 o.custid
)COUNT(), AVG(), SUM()
과 같은 집계함수위의 두가지 경우에만 사용할 수 있다.
그렇다면 다시 위의 쿼리로 돌아갔을 때 잘못된 점이 보일 것이다.
GROUP BY
에 선언되지 않은 컬럼, 집계함수도 아닌 컬럼인 c.name
으로 인해 문제가 발생한 것이다.
문제를 해결하기 위해서는
GROUP BY
에 추가SELECT
o.custid
, c.name
, MAX(o.payment)
FROM orders AS o, customers AS c
WHERE o.custid = c.custid
//GROUP BY o.custid
GROUP BY o.custid, c.name
SELECT
o.custid
, ANY_VALUE(c.name)
, MAX(o.payment)
FROM orders AS o, customers AS c
WHERE o.custid = c.custid
GROUP BY o.custid
sql_mode
옵션 중 only_full_group_by
비활성화🧷 참고자료
✍️ 추가 스터디