🎯 목표
GROUP BY 절에 대해 알아보고 그룹 함수를 사용하여 데이터를 추출해본다.

1. GROUP BY 절

특정 컬럼을 기준으로 그룹화를 하면 집계함수의 활용범위를 넓힐 수 있다. 그룹화 없이 집계함수를 사용한다면 집계 대상이 전체 데이터였다.(WHERE 절에 조건식이 존재한다면 WHERE절로 필터링된 후의 데이터) 그룹화를 하면 학년별 평균 점수, 연령대별 평균 몸무게 등을 계산할 수 있다.

(1) 기본 구조

SELECT 컬럼1, ...
FROM 테이블
GROUP BY 컬럼1

쿼리를 작성할 때, 여러 절을 사용하게 되는데 배치해야하는 순서는 다음과 같다.
SELECT - FROM - WHERE - GROUP BY - HAVING - ORDER BY - LIMIT

(2) 예제로 이해하기

Fig 1. 예시(테이블명: Products)


위 이미지(Fig 1)를 보면 Products 테이블에서 카테고리를 기준으로 그룹화했을 때 중복된 항목이 하나의 값으로 대표되는 것을 볼 수 있다. GROUP BY를 지정하면 DISTINCT를 했을 때처럼 중복이 제거되는 효과가 있다.

🤔 집계되지 않은 컬럼 불러오기

만약, 집계함수를 사용하지 않으면 어떤 데이터가 불러와질까? 라는 의문이 생겨서 직접 MySQL Workbench를 이용해서 테이블을 만들고, 실험해 보기로 했다.
cf. 테이블을 생성할 때 작성한 쿼리는 하단에 위치한 댓글창에 작성해 두었다.

Fig 2. 실험 전, 테이블(Products) 생성


SELECT *
FROM test.Products
GROUP BY category

테이블을 먼저 생성하고 위 쿼리를 실행했을 때 ‘Error Code: 1055. Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘test.Products.Product_name’ which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by’ 라는 에러 메시지가 떴다. 에러 메시지를 해석해보면 그룹화되지 않은 또는 집계함수가 사용되지 않은 컬럼을 불러올 수 없다는 것이다.

프로그래머스에서 MySQL 문제를 풀면 그룹화되지 않고(집계처리도 안된) 컬럼을 출력했을 때, 첫 번째 행이 대표로 출력되는 것을 확인했었다. 만약 집계처리되지 않은 컬럼도 출력하고 싶을 땐 sql_mode가 only_full_group_by 모드로 설정되어있는 것을 해제해주면 된다. 쿼리 앞에 SET sql_mode = ''; 를 추가하면 그룹화된 컬럼만 출력해야하는 모드가 해제된다.

Fig 3. sql_mode=only_full_group_by 해제 후


위 이미지(Fig 3)을 보면 그룹화되지 않은(또는 집계처리되지 않은) 컬럼은 그룹화된 컬럼 기준 첫 번째 행이 대표로 불러와진다.


2. 그룹 함수

MySQL에서 사용하는 대표적인 그룹 함수는 다음과 같다. 각 그룹 함수에 대해 위에서 생성한 테이블(Products)에 적용해 보았다.

(1) COUNT

COUNT 함수는 특정 필드에 대한 데이터의 건수를 출력한다. 전체 컬럼을 의미하는 *를 입력한다면 전체 행의 수를 출력하고, 특정 컬럼명을 입력하면 NULL값을 제외한 데이터의 수를 출력한다.

SELECT category, COUNT(price) AS cnt
FROM test.Products
GROUP BY category
Fig 4. 위 쿼리의 실행 결과

(2) SUM

SUM 함수는 특정 필드에 대한 합을 출력한다. 전체 컬럼을 의미하는 *를 입력하면 에러사인이 뜬다. 만약 SUM 함수에 숫자가 아닌 자료형을 사용하면 값이 0으로 출력된다.

SELECT category, SUM(price) AS total_price
FROM test.Products
GROUP BY category
Fig 5. 위 쿼리의 실행 결과

(3) AVG

AVG 함수는 특정 필드에 대한 평균값을 출력한다. SUM 함수와 동일하게 숫자가 아닌 자료형을 사용하면 값이 0으로 출력된다.
cf. SUM/COUNT 값과 동일한 값을 출력한다.

SELECT category, AVG(price) AS avg_price
FROM test.Products
GROUP BY category
Fig 6. 위 쿼리의 실행 결과

(4) MIN, MAX

MIN, MAX 함수는 특정 필드의 최솟값과 최댓값을 출력한다. 이때 문자열이 담긴 필드를 함수에 입력하면 정의된 정렬 순서를 기준으로 값이 출력된다.

  • 한글: 자음 < 모음 < 한글 (한글이 가장 큰 값)
  • 영문: 대문자 < 소문자 (소문자가 가장 큰 값)
SELECT category, MIN(price) AS min_price, MAX(price) AS max_price
FROM test.Products
GROUP BY category
Fig 7. 위 쿼리의 실행 결과

🤔 문자열의 최솟값과 최댓값

SELECT category, MIN(product_name), MAX(product_name)
FROM test.Products
GROUP BY category
Fig 8. 위 쿼리의 실행 결과

(5) GROUP_CONCAT

GROUP_CONCAT 함수는 그룹화된 컬럼을 기준으로 특정 필드값의 요소를 한 줄로 표현할 수 있다. 이는 그룹화 후 문자열을 합칠 때 사용된다.

SELECT category, GROUP_CONCAT(product_name) AS product_list
FROM test.Products
GROUP BY category
Fig 9. 위 쿼리의 실행 결과


GROUP_CONCAT은 따로 구분자를 지정하지 않으면 ‘,’를 기준으로 문자열이 합쳐진다. 구분자를 지정하는 방법은 필드명 뒤에 SEPARATOR '구분자'를 추가하면 된다. 구분자를 공백으로 바꾸려면 아래와 같이 쿼리를 작성하면 된다.

SELECT category, GROUP_CONCAT(product_name SEPARATOR ' ') AS product_list
FROM test.Products
GROUP BY category
Fig 10. 위 쿼리의 실행 결과


3. Reference

👩🏻‍💻개인 공부 기록용 블로그입니다
오류나 틀린 부분이 있을 경우 댓글 혹은 메일로 따끔하게 지적해주시면 감사하겠습니다.

댓글남기기