DataBase

[SQL] 집계함수, GROUP BY, HAVING

Beencle 2023. 3. 21. 15:58

여러 행들의 그룹이 모여서 그룹당 단 하나의 결과를 돌려준다.

  • 여러 행들의 그룹이 모여서 그룹당 단 하나의 결과를 돌려주는 함수
  • GROUP BY 절은 행들을 소그룹화 한다.
집계 함수명 ( DISTINCT 칼럼이나 표현식 )
  • ALL : Default 옵션이므로 생략 가능함
  • DISTINCT : 같은 값을 하나의 데이터로 간주할 때 사용하는 옵션임
  • 자주 사용되는 주요 집계 함수들은 다음과 같다.

집계함수 종류

집계 함수 설명
COUNT(*) NULL 값을 포함한 행의 수
COUNT(표현식) 표현식이 NULL을 제외한 행의 
SUM([DISTINCT | ALL] 표현식) 표현식이 NULL을 제외한 합계 출력
AVG([DISTINCT | ALL] 표현식) 표현식이 NULL을 제외한 평균 출력
MAX([DISTINCT | ALL] 표현식) 표현식의 최대값 출력
(날짜,문자 데이터 포함)
MIN([DISTINCT | ALL] 표현식) 표현식의 최소값 출력
(날짜,문자 데이터 포함)
STDDEV([DISTINCT | ALL] 표현식) 표현식의 표준편차를 출력
VARIAN([DISTINCT | ALL] 표현식) 표현식의 분산을 출력

GROUP BY , HAVING문

  • 그룹별로 집계된 정보를 출력하고 비교할 때 GROUP BY가 사용됩니다.
  • 나누고자 하는 그룹의 컬럼명을 SELECT절과 GROUP BY절 뒤에 추가하면 된다.
  • 집계함수와 함께 사용되는 상수는 GROUP BY 절에 추가하지 않아도 된다.
  • GROUP BY 절에 의한 소그룹별로 만들어진 집계 데이터 중, HAVING 절에서 제한 조건을 두어 조건을 만족하는 내용만 출력한다. - HAVING 절은 일반적으로 GROUP BY 절 뒤에 위치한다.
SELECT  [DISTINCT] 칼럼명  [ALIAS명]
FROM 테이블명  
[WHERE 조건식 ]  
[GROUP BY 칼럼(Column)이나 표현식]  
[HAVING 그룹조건식];

[예제]

SELECT POSITION 포지션, 
	COUNT(*) 인원수, 
	COUNT(HEIGHT) 키대상, 
	MAX(HEIGHT) 최대키, 
	MIN(HEIGHT) 최소키, 
	ROUND(AVG(HEIGHT),2) 평균키 
FROM PLAYER 
GROUP BY POSITION;

[예제2]

SELECT POSITION 포지션, 
	ROUND(AVG(HEIGHT),2) 평균키 
FROM PLAYER 
WHERE AVG(HEIGHT) >= 180 
GROUP BY POSITION;

위의 예제2 코드는 에러가 발생한다. 이유는 WHERE절에는 집계함수를 사용할 수 없기 때문이다.

WHERE 절은 FROM 절에 정의된 집합(주로 테이블)의 개별 행에 WHERE 절의 조건절이 먼저 적용되고, WHERE 절의 조건에 맞는 행이 GROUP BY 절의 대상이 된다. 그런 다음 결과 집합의 행에 HAVING 조건절이 적용된다. 결과적으로 HAVING 절의 조건을 만족하는 내용만 출력된다. 즉, HAVING 절은 WHERE 절과 비슷하지만 그룹을 나타내는 결과 집합의 행에 조건이 적용된다는 점에서 차이가 있다.

 

[예제2-1]

SELECT POSITION 포지션, 
	ROUND(AVG(HEIGHT),2) 평균키 
FROM PLAYER 
GROUP BY POSITION
HAVING AVG(HEIGHT) >= 180;

이렇게 WHERE을 HAVING으로 바꾸면 정상 작동된다.

HAVING절과 GROUP BY절의 순서를 바꿔도 정상 작동 되지만 순서를 보면 그룹핑이 된 다음에 조건에 맞게 걸러지는게 맞으므로 순서를 위처럼 맞춰주는게 낫다.

그렇다고 GROUP BY이 있는 쿼리에서 WHERE을 사용하지 못하는건 아니다. 

SELECT TEAM_ID 팀ID, COUNT(*) 인원수 FROM PLAYER WHERE TEAM_ID IN ('K09', 'K02') GROUP BY TEAM_ID;

SELECT TEAM_ID 팀ID, COUNT(*) 인원수 FROM PLAYER GROUP BY TEAM_ID HAVING TEAM_ID IN ('K09', 'K02');

위의 두 쿼리문은 같은 결과를 도출하지만 하나는 WHERE 조건식을 사용하고 하나는 HAVING을 사용했다.

권하는 방식은 WHERE을 사용하는 방법을 권한다. 이유는 GROUP BY를 통해 그룹핑을 하기전에 WHERE을 사용해서 그룹핑할 데이터의 양을 줄이고 집계하는 것이 효율적인 자원에 이점이 있기 때문이다.