MariaDB / 함수 / COUNT, SUM, AVG, MAX, MIN

MariaDB에서 COUNT는 개수, SUM은 합계, AVG는 평균, MAX와 MIN은 최댓값과 최솟값을 구합니다. COUNT(*)는 모든 행을 세지만 COUNT(열)과 나머지 함수는 해당 열의 NULL을 제외합니다. 따라서 0점과 아직 알 수 없는 NULL을 같은 값으로 취급하면 집계 결과의 의미가 달라집니다.

다섯 집계 함수의 차이와 실습 데이터

함수 구하는 값 주의점
COUNT(*) 원본 행의 개수 열에 NULL이 있어도 행을 셉니다.
COUNT(score) score가 NULL이 아닌 행 수 0점도 셉니다.
SUM(score) 점수의 합 행의 개수를 세는 함수가 아닙니다.
AVG(score) NULL을 제외한 점수 평균 전체 행 수로 나누는 것과 다를 수 있습니다.
MAX(score), MIN(score) 가장 큰 점수와 작은 점수 그 점수를 가진 행 전체를 반환하지는 않습니다.

MariaDB 서버와 SQL 클라이언트, 접근 가능한 learning 실습 DB를 준비합니다. 다음 SQL을 한 번 실행한 뒤 같은 DB에서 뒤의 SELECT를 실행하세요. 이미 같은 이름의 테이블이 있으면 보존할 자료를 지우지 말고 별도 실습 환경을 사용합니다. 가상의 점수 5행이며 실제 성적이나 통계가 아닙니다.

USE learning;
CREATE TABLE scores_aggregate_demo (
    id INT PRIMARY KEY,
    team CHAR(1) NOT NULL,
    score DECIMAL(8,2) NULL
);
INSERT INTO scores_aggregate_demo VALUES
    (1, 'A', 10), (2, 'A', 20),
    (3, 'B', 20), (4, 'B', NULL), (5, 'B', 0);

점수는 10·20·20·NULL·0입니다. 같은 20점 두 건은 서로 다른 행이고, NULL은 점수를 모르는 상태, 0은 알려진 점수가 0인 상태로 구분했습니다. 이 차이를 기준으로 뒤의 결과를 비교합니다.

COUNT로 전체·알려진 값·서로 다른 값 세기

SELECT COUNT(*) AS all_rows,
       COUNT(score) AS known_scores,
       COUNT(DISTINCT score) AS distinct_scores
FROM scores_aggregate_demo;

결과는 all_rows 5, known_scores 4, distinct_scores 3입니다. COUNT(score)는 NULL 한 건을 제외하지만 0은 포함합니다. COUNT(DISTINCT score)는 0·10·20이라는 서로 다른 값 세 개만 세고 NULL은 제외합니다. 행 수와 고유한 값의 개수는 서로 다른 질문입니다.

NULL인 행만 확인하려면 WHERE score IS NULL 조건을 사용합니다. NULL과 숫자 0을 같은 것으로 가정하거나 score = NULL로 비교하지 마세요. 함수의 기본 정의는 COUNT와 COUNT DISTINCT 문서에 있습니다.

SUM과 AVG에서 NULL·0·DISTINCT 비교

SELECT SUM(score) AS total_score,
       ROUND(AVG(score), 2) AS average_score,
       ROUND(AVG(COALESCE(score, 0)), 2) AS average_with_zero
FROM scores_aggregate_demo;

합계는 50.00이고 평균은 50을 알려진 네 점수로 나눈 12.50입니다. NULL을 COALESCE로 0으로 바꾸고 평균을 내면 다섯 값으로 나누어 10.00이 됩니다. 이는 단순 표시 방식 변경이 아니라 계산에 포함되는 값의 의미를 바꾼 것입니다. 미입력 점수를 0점으로 처리해도 되는지 정책을 먼저 정해야 합니다.

SUM은 숫자 값들의 합을 구하며, AVG는 NULL을 제외한 값의 산술평균을 구합니다. 예제는 비교하기 쉽게 평균만 소수 둘째 자리로 반올림했습니다. NULL 처리와 반환 조건은 SUM 문서와 AVG 문서를 참고하세요.

SELECT SUM(DISTINCT score) AS distinct_total,
       ROUND(AVG(DISTINCT score), 2) AS distinct_average
FROM scores_aggregate_demo;

DISTINCT를 붙인 합계는 0+10+20인 30.00이고 평균은 10.00입니다. 같은 값 20을 한 번만 계산하기 때문입니다. 실제로 서로 다른 사람이나 거래가 같은 수치를 가질 수 있으므로, 중복 행 문제를 해결하려고 SUM(DISTINCT 금액)을 무조건 붙이면 정상 값을 누락할 수 있습니다. 무엇이 중복인지 식별 기준부터 확인해야 합니다.

MAX·MIN과 그 값을 가진 행 조회

SELECT MAX(score) AS maximum_score, MIN(score) AS minimum_score
FROM scores_aggregate_demo;

SELECT id, team, score
FROM scores_aggregate_demo
WHERE score = (SELECT MAX(score) FROM scores_aggregate_demo)
ORDER BY id;

첫 쿼리는 최댓값 20.00과 최솟값 0.00인 한 행을 반환합니다. 두 번째는 그 최댓값을 가진 원본 행을 조회하므로 ID 2의 A팀, ID 3의 B팀이 모두 나옵니다. 동률이면 행이 여러 개라는 점을 확인할 수 있습니다.

MAX(score) 옆에 team을 GROUP BY 없이 넣는다고 최댓값을 가진 팀이 자동으로 선택되는 것은 아닙니다. 팀이 어떤 행에서 왔는지 명확하지 않거나 SQL 모드에 따라 오류가 날 수 있습니다. 반대로 ORDER BY score DESC LIMIT 1은 한 행을 선택하므로 동률을 모두 보여 주는 두 번째 쿼리와 목적이 다릅니다.

MAX와 MIN은 문자열·날짜에도 사용할 수 있지만 문자열은 비교 규칙과 자료형의 영향을 받습니다. 숫자를 문자열로 저장하면 숫자 크기를 비교하려는 의도와 달라질 수 있습니다. 자세한 조건은 MAX 문서와 MIN 문서를 참고하세요.

그룹별 결과와 입력이 없는 경우

SELECT team, COUNT(*) AS row_count, COUNT(score) AS known_scores,
       SUM(score) AS total_score, ROUND(AVG(score), 2) AS average_score,
       MAX(score) AS maximum_score, MIN(score) AS minimum_score
FROM scores_aggregate_demo
GROUP BY team
ORDER BY team;

A팀은 2행·알려진 값 2개·합계 30.00·평균 15.00·최대 20.00·최소 10.00입니다. B팀은 3행·알려진 값 2개·합계 20.00·평균 10.00·최대 20.00·최소 0.00입니다. 팀별 그룹은 원본을 변경하지 않고 결과의 집계 단위를 나눕니다. 기준과 필터 순서는 GROUP BY와 WHERE·HAVING 비교에서 확인할 수 있습니다.

SELECT COUNT(*) AS row_count, COUNT(score) AS known_scores,
       SUM(score) AS total_score, AVG(score) AS average_score,
       MAX(score) AS maximum_score, MIN(score) AS minimum_score
FROM scores_aggregate_demo
WHERE team = 'C';

C팀에 해당하는 행이 없으므로 row_count와 known_scores는 0, 나머지 네 집계값은 NULL인 한 행이 나옵니다. 이 예제는 GROUP BY가 없는 전체 집계입니다. GROUP BY로 묶었는데 조건에 맞는 원본 행이 하나도 없으면 그룹 결과 행 자체가 생기지 않는 경우와 구분하세요.

NULL 결과를 화면에 0으로 보여 주려면 COALESCE(SUM(score), 0) 같은 방식을 검토할 수 있지만, 데이터가 없다는 사실을 숨겨도 되는지 먼저 정해야 합니다. 집계 결과가 예상과 다르면 WHERE 조건으로 빠진 행, NULL 수, JOIN으로 늘어난 행 수와 DISTINCT 적용 대상을 확인합니다. 함수 이름을 바꾸기 전에 집계하려는 데이터 단위가 맞는지 보는 것이 중요합니다.