MySQL - 특정 column을 기준으로 그룹화 (GROUP BY, HAVING)

사람·2025년 1월 18일

MySQL

목록 보기
2/8

GROUP BY 절에 어떤 column을 지정하면, 해당 column에 동일한 값을 가지는 데이터들은 하나로 묶여서 조회된다.

SELECT column_name(s)
FROM table_name
WHERE condition
GROUP BY column_name(s)
HAVING condition
ORDER BY column_name(s);

위와 같은 기본 형태로 사용하면 DISTICNT 절과 큰 차이가 없지만, (중복 값은 그룹화해 하나로 조회하기 때문.) 보통은 SUM, COUNT, AVG 등의 집계 함수와 함께 사용한다. 그룹별 집계 결과를 알고자 할 때 사용하는 것.

WHERE 절에는 GROUP BY를 수행하기 이전의 조건을 지정하고,
HAVING 절에는 GROUP BY를 수행한 이후의 조건을 지정한다.
지정할 조건이 없다면 생략하면 된다.

SELECT COUNT(CustomerID), Country
FROM Customers
GROUP BY Country
HAVING COUNT(CustomerID) > 5
ORDER BY COUNT(CustomerID) DESC;
# Country를 기준으로 그룹화한 후,
# 각 그룹에 속한 CustmerID 데이터가 5개를 초과하는 그룹에 대한 개수를 조회.
SELECT Employees.LastName, COUNT(Orders.OrderID) AS NumberOfOrders
FROM Orders
INNER JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID
WHERE LastName = 'Davolio' OR LastName = 'Fuller'
GROUP BY LastName
HAVING COUNT(Orders.OrderID) > 25;
# LastName이 'Davolio' 또는 'Fuller'인 경우에 대해서만 그룹화,
# 그룹화된 결과에서 Orders.OrderID 데이터의 개수가 25를 초과하는 경우에 대해서만 조회.

예제 출처: https://www.w3schools.com/mysql/mysql_having.asp

위 링크에서 이 예제들을 직접 실행시켜볼 수 있다.


GROUP BY를 사용할 때 반드시 유념해야 할 점이 있다.

  1. GROUP BY에 명시된 컬럼은 반드시 SELECT에 포함되어야 한다.
  2. GROUP BY에 정의한 내용(컬럼 또는 변형된 컬럼)만 SELECT절에 그대로 사용할 수 있다. GROUP BY에 정의하지 않은 컬럼을 SELECT절에서 사용하려면 반드시 집계함수 처리를 해야 한다.

위 내용을 준수하지 않고 쿼리를 작성하더라도 MySQL이 오류를 발생시키지는 않지만, 사실 MySQL이 아닌 다른 상용 DBMS에서는 그러한 쿼리는 실행조차 되지 않는다고 한다. MySQL의 경우 에러 없이 실행은 되지만 임의의 값을 넣어 보여주기 때문에 원하는 결과가 아닐 가능성이 매우 높다.
에러가 나지 않기 때문에 문제를 발견하지 못하는 경우가 많아 주의가 필요하다.

예를 들어 다음의 쿼리를 보자.

SELECT department_id, first_name
FROM employees
GROUP BY department_id;

위 쿼리는 MySQL에서 에러 없이 실행된다.

위 쿼리를 작성한 사람은 각 department_id 그룹 내의 모든 first_name 데이터가 조회되기를 기대했을지도 모른다.
하지만 실제로는 first_name 값은 동일한 department_id 그룹 내에서 임의의 하나의 값만 반환되게 된다. 즉, 동일한 department_id에 여러 first_name이 있을 경우 어떤 값이 반환될지 알 수 없는 것이다.

위 문제를 해결하기 위한 방법들은 다음과 같다.

0. ONLY_FULL_GROUP_BY 모드를 켜기
ONLY_FULL_GROUP_BY 모드를 켜면 MySQL의 SQL 표준 준수를 강제해 예상치 못한 동작을 방지할 수 있다.

ERROR 1055 (42000): 'employees.first_name' isn't in GROUP BY

ONLY_FULL_GROUP_BY 모드가 켜진 상태에서 위 쿼리를 실행하면 에러가 발생하기 때문에 문제를 바로 인지할 수 있다.
따라서 이 모드를 켜는 것을 권장한다.
켜는 방법은 이 글의 골자가 아니니 직접 검색해서 찾아보시길...

1. GROUP BY에 명시적으로 모든 비집계 컬럼을 포함하기

SELECT department_id, first_name
FROM employees
GROUP BY department_id, first_name;

이렇게 하면 각 department_id 그룹 내의 모든 first_name 데이터가 조회된다.

2. 집계 함수 사용하기

SELECT department_id, MAX(first_name) AS first_name
FROM employees
GROUP BY department_id;

이렇게 하면 각 department_id 그룹 내에서 first_name에 대한 집계 함수를 사용한 결과가 조회된다.

3. ANY_VALUE() 사용하기

SELECT department_id, ANY_VALUE(first_name) AS first_name
FROM employees
GROUP BY department_id;

이렇게 하면 department_id 그룹 내에서 임의의 하나의 first_name 값만 반환된다.


위키 독스의 글을 일부 참고했다. 좋은 글이니 다들 정독하셔서 행복한 GROUP BY 생활 되시길~

profile
알고리즘 블로그 아닙니다.

0개의 댓글