[프로그래머스] SQL 고득점 Kit - GROUP BY

박채은·2023년 6월 22일
0

코딩테스트

목록 보기
46/52

GROUP BY

  • 테이블의 레코드를 grouping하기 위해 사용된다.
  • 해당 절은 각각의 그룹에 대해 하나의 행을 만드는데 이 과정을 aggregation이라 부른다.
  • GROUP BY는 주로 집계함수인 COUNT, MAX, MIN, SUM, AVG와 함께 쓰인다.
  • GROUP BY 절에서 기준 칼럼을 여러 개 지정할 수 있다.
  • HAVING 절을 함께 사용하여 WHERE 절의 조건절처럼 조건을 부여할 수 있다.

https://eminentstar.github.io/2017/06/24/select-groupby.html
https://gent.tistory.com/505

🚨 주의해야할 점

  • SELECT 절에는 GROUP BY에 쓰인 column과 집계함수(COUNT, MAX, MIN, SUM, AVG) 만 사용가능하다.
    • 집계 함수의 통계 정보는 NULL 값을 가진 행을 제외하고 수행한다.
  • GROUP BY 절에서는 SELECT 절과는 달리 ALIAS 명을 사용할 수 없다.
    • GROUP BY 절에서는 SELECT 절의 ALIAS를 사용할 수는 있다.
    • GROUP BY 절에서 반드시 ALIAS를 사용해야 한다면, FROM 절에 INLINE VIEW를 생성해서 사용한다.
  • WHERE 절에는 집계 함수를 사용할 수 없다.
  • WHERE 절은 전체 데이터를 GROUP으로 나누기 전에 행들을 미리 제거시킨다.
  • GROUP BY 절에 의한 소그룹별로 만들어진 집계 데이터 중, HAVING 절에서 제한 조건을 두어 조건을 만족하는 내용만 출력한다.

having

  • having은 그룹화 또는 집계가 발생한 후 레코드를 필터링하는데 사용된다.
    • having은 집계 절과 함께 사용될 수 있다.
    • having은 GROUP BY 없이도 사용될 수 있다.
  • where은 그룹화 또는 집계가 발생하기 전에 레코드를 필터링하는데 사용된다.
    • where은 집계 함수와 함께 사용될 수 없다.(COUNT, MAX, MIN, SUM, AVG)

WHERE 절로 가장 처음에 row들을 필터링하고, 그 후에 그룹핑까지 거친 후에 HAVING 절에서 그 조회된 그룹들을 다시 필터링한다.


쿼리 작성 및 실행 순서

SELECT - 5순위 (필수)
FROM - 1순위 (필수)
WHERE - 2순위
GROUP BY - 3순위
HAVING - 4순위
ORDER BY - 6순위

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY

실행 순서에 따른 이슈
Alias 이슈

GROUP BY와 NULL


1. 성분으로 구분한 아이스크림 총 주문량

  • 아이스크림 성분 타입과 성분 타입에 대한 아이스크림의 총 주문량을 출력한다.
  • 총 주문량이 작은 순서대로 조회
SELECT INGREDIENT_TYPE, sum(TOTAL_ORDER) as TOTAL_ORDER
from FIRST_HALF A
inner join ICECREAM_INFO B
on A.FLAVOR = B.FLAVOR
group by INGREDIENT_TYPE
order by TOTAL_ORDER

2. 고양이와 개는 몇 마리 있을까

SELECT ANIMAL_TYPE, count(ANIMAL_TYPE) as count
from ANIMAL_INS
group by ANIMAL_TYPE
order by ANIMAL_TYPE;

3. 동명 동물 수 찾기

  • 동물의 이름 중 두 번 이상 쓰인 이름과 해당 이름이 쓰인 횟수를 조회
  • 이름이 없는 동물은 집계에서 제외
  • 이름 순으로 정렬
SELECT NAME, count(name) as count
from ANIMAL_INS
where NAME is not null
group by NAME
having count(name) >= 2
order by NAME

4. 입양 시각 구하기(1)

  • 09:00부터 19:59까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문
  • 시간대 순으로 정렬
SELECT HOUR(DATETIME) as HOUR, count(HOUR(DATETIME)) as COUNT
from ANIMAL_OUTS
where HOUR(DATETIME) >= 9 and HOUR(DATETIME) <=19
group by HOUR(DATETIME)
order by HOUR /* SELECT이 먼저 실행되기 때문에 HOUR라고 작성해도 된다. */

[ 다른 사람의 코드 ]

SELECT HOUR(DATETIME) HOUR, COUNT(DATETIME) COUNT
FROM ANIMAL_OUTS
GROUP BY HOUR(DATETIME)
HAVING HOUR >= 9 and HOUR <= 19 /* SELECT 절의 HOUR alias를 사용한다. */
order by HOUR
  • HAVING HOUR >= 9 and HOUR <= 19 을 작성했는데, HAVING이 SELECT 보다 먼저 실행되는데 SELECT에서 사용된 alias를 사용해도 문제가 발생하지 않는지?
    • MySQL에서는 Having을 평가하기 전에, SELECT 절의 일부를 평가하기 때문에 가능했던 것이다.
    • WHERE 절은 SELECT 절 보다 먼저 실행된다는 이유로 SELECT 절의 Alias를 사용할 수 없다.
    • HAVING 절은 사용할 수 있다.

⭐️ SELECT의 alias는 GROUP BY, HAVING, ORDER BY에서만 사용 가능하다!!
1. ORDER BY: SELECT 보다 나중에 실행되기 때문에
2. GROUP BY, HAVING: SELECT보다 먼저 실행되지만, MySQL이 미리 SELECT 절을 살펴보기 때문에 사용 가능하다.

⭐️ WHERE 절에서는 SELECT alias를 사용할 수 없고, 실제 컬럼명만 사용해야 한다.
서브 쿼리를 통해서 사용할 수는 있다.

https://stackoverflow.com/questions/49888360/using-alias-in-the-where-and-having-statements
HAVING 절에서 SELECT 절의 Alias를 사용할 수 있는 이유


재구매가 일어난 상품과 회원 리스트 구하기

SELECT USER_ID, PRODUCT_ID
from ONLINE_SALE
group by USER_ID, PRODUCT_ID
having count(*) >= 2
order by USER_ID, PRODUCT_ID desc;
  • 어떤 유저가 해당 물품을 재구매했는지를 확인하고, 출력하는 문제이다.
  • 처음에는 중첩 select 문을 써야하나 했는데, 다음과 같이 간단하게 풀 수 있었다.
    => 재구매, 중복의 경우에는 count(*)를 써서 해결해보자

시행착오

SELECT USER_ID, PRODUCT_ID
from ONLINE_SALE
group by (USER_ID, PRODUCT_ID) /* ❗️ 문제 발생 */
having count((USER_ID, PRODUCT_ID)) >= 2 /* ❗️ 문제 발생 */
order by USER_ID, PRODUCT_ID desc;
  • group by (USER_ID, PRODUCT_ID) -> group by USER_ID, PRODUCT_ID
  • count((USER_ID, PRODUCT_ID)) >= 2 -> count(*)
    • count에는 하나의 요소만을 넣을 수 있다.
    • 해당 그룹에 대해서 값을 count할꺼면, count(*)로 작성하면 된다.

[참고]
https://food4ithought.com/2019/01/28/group-by-%EC%A0%88%EC%9D%98-alias-%EC%82%AC%EC%9A%A9-%EC%A0%9C%ED%95%9C-%EC%8B%9C-%EB%8C%80%EC%95%88/

0개의 댓글