GROUP BY - MySQL 풀이

송철진·2023년 3월 18일
0

프로그래머스-MySQL

목록 보기
6/7

Lv.2

동명 동물 수 찾기

SELECT
    NAME,
    COUNT(NAME) AS COUNT
FROM ANIMAL_INS
WHERE NOT NAME IS NULL
GROUP BY NAME
HAVING COUNT(NAME) > 1
ORDER BY NAME

SELECT - 동물 보호소에 들어온 동물 이름 중 두 번 이상 쓰인 이름과 해당 이름이 쓰인 횟수를 조회
WHERE - 이때 결과는 이름이 없는 동물은 집계에서 제외하며,
ORDER BY - 결과는 이름 순으로

자동차 종류 별 특정 옵션이 포함된 자동차 수

SELECT CAR_TYPE, COUNT(CAR_TYPE) AS CARS
FROM CAR_RENTAL_COMPANY_CAR
WHERE 
    OPTIONS LIKE '%통풍시트%' 
    OR OPTIONS LIKE '%열선시트%' 
    OR OPTIONS LIKE '%가죽시트%'
GROUP BY CAR_TYPE
ORDER BY CAR_TYPE

FROM - CAR_RENTAL_COMPANY_CAR 테이블에서
WHERE - '통풍시트', '열선시트', '가죽시트' 중 하나 이상의 옵션이 포함된 자동차가
SELECT - 자동차 종류 별로 몇 대인지 출력. 이때 자동차 수에 대한 컬럼명은 CARS로 지정
ORDER BY - 결과는 자동차 종류를 기준으로 오름차순 정렬.

진료과별 총 예약 횟수 출력하기

SELECT 
    MCDP_CD AS '진료과 코드', 
    COUNT(APNT_YMD) AS '5월예약건수'
FROM APPOINTMENT
WHERE DATE_FORMAT(APNT_YMD, '%Y-%m') = '2022-05'
GROUP BY MCDP_CD
ORDER BY COUNT(APNT_YMD), MCDP_CD

FROM - APPOINTMENT 테이블에서
WHERE - 2022년 5월에 예약한
SELECT - 환자 수를 진료과코드 별로 조회. 이때, 컬럼명은 '진료과 코드', '5월예약건수'로 지정
ORDER BY - 결과는 진료과별 예약한 환자 수를 기준으로 오름차순 정렬하고, 예약한 환자 수가 같다면 진료과 코드를 기준으로 오름차순 정렬.

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

SELECT 
    ANIMAL_TYPE,	
    COUNT(ANIMAL_TYPE) AS count
FROM ANIMAL_INS
GROUP BY ANIMAL_TYPE
ORDER BY ANIMAL_TYPE

FROM - 동물 보호소에 들어온 동물 중
SELECT, GROUP BY - 고양이와 개가 각각 몇 마리인지 조회
ORDER BY - 이때 고양이를 개보다 먼저 조회해주세요.

고양이를 먼저 조회하려면, 고양이(Cat)가 개(Dog)보다 알파벳 순서가 앞이므로 ANIMAL_TYPE을 기준으로 오름차순 정렬하면 된다.

입양 시각 구하기(1)

SELECT 
    DATE_FORMAT(DATETIME, '%H') AS HOUR, 
    COUNT(DATE_FORMAT(DATETIME, '%H')) AS COUNT
FROM ANIMAL_OUTS
WHERE 
	DATE_FORMAT(DATETIME, '%H') >= 9 
    AND DATE_FORMAT(DATETIME, '%H') <= 19
GROUP BY DATE_FORMAT(DATETIME, '%H')
ORDER BY DATE_FORMAT(DATETIME, '%H')

보호소에서는 몇 시에 입양이 가장 활발하게 일어나는지 알아보려 합니다.

WHERE - 09:00부터 19:59까지,
SELECT - 각 시간대별로 입양이 몇 건이나 발생했는지 조회
ORDER BY - 이때 결과는 시간대 순으로 정렬

문제 예시)에서는 HOUR 값이 9 ~ 19로 되어있어서 한자리 수일 때는 '09'가 아닌 '9'가 되도록 %k로 구현해야 하는가 싶었는데 %H로 구현해도 딱히 상관없었던 모양이다.

가격대 별 상품 개수 구하기

FROM - PRODUCT 테이블에서
SELECT - 만원 단위의 가격대 별로 상품 개수를 출력
이때 컬럼명은 각각 컬럼명은 PRICE_GROUP, PRODUCTS로 지정
가격대 정보는 각 구간의 최소금액(10,000원 이상 ~ 20,000 미만인 구간인 경우 10,000)으로 표시.
ORDER BY - 결과는 가격대를 기준으로 오름차순 정렬.

답은 맞았으나 망한 풀이:

SELECT
    CASE 
        WHEN PRICE >= 0 AND PRICE < 10000 THEN 0
        WHEN PRICE >= 10000 AND PRICE < 20000 THEN 10000
        WHEN PRICE >= 20000 AND PRICE < 30000 THEN 20000
        WHEN PRICE >= 30000 AND PRICE < 40000 THEN 30000 
        WHEN PRICE >= 40000 AND PRICE < 50000 THEN 40000
        WHEN PRICE >= 50000 AND PRICE < 60000 THEN 50000
        WHEN PRICE >= 60000 AND PRICE < 70000 THEN 60000 
        WHEN PRICE >= 70000 AND PRICE < 80000 THEN 70000
        WHEN PRICE >= 80000 AND PRICE < 90000 THEN 80000
    ELSE 90000
    END AS PRICE_GROUP,    
    COUNT(PRICE) AS PRODUCTS
FROM PRODUCT
GROUP BY PRICE_GROUP
ORDER BY PRICE_GROUP

이걸 TRUNCATE(숫자, 버릴 자리수)를 사용하면 간단히 줄일 수 있다.
버릴자리수가 양수면 소수점이하 n번째 자리수를, 음수면 소수점 이상 n번째 자리수를 의미한다

예) PRICE = 10000원 ~ 19999원 일 때,
TRUNCATE(PRICE, -4) = 1이므로 최소값을 기준으로 그룹핑할 수 있다.

SELECT
    TRUNCATE(PRICE, -4) AS PRICE_GROUP,    
    COUNT(PRICE) AS PRODUCTS
FROM PRODUCT
GROUP BY PRICE_GROUP
ORDER BY PRICE_GROUP

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

SELECT - 상반기 동안 각 아이스크림 성분 타입과 성분 타입에 대한 아이스크림의 총주문량(총주문량을 나타내는 컬럼명은 TOTAL_ORDER로 지정)을
ORDER BY - 총주문량이 작은 순서대로 조회.

SELECT 
    INGREDIENT_TYPE,	
    SUM(TOTAL_ORDER) AS TOTAL_ORDER
FROM FIRST_HALF fh
INNER JOIN ICECREAM_INFO ii ON fh.FLAVOR = ii.FLAVOR
GROUP BY INGREDIENT_TYPE
ORDER BY TOTAL_ORDER

각 테이블의 기본키, 참조키가 같다는 조건하에 두 테이블을 JOIN하고
성분타입(INGREDIENT_TYPE)을 기준으로 그룹핑하여
총주문량(TOTAL_ORDER)의 합(SUM())을 각각 계산하고
총주문량(TOTAL_ORDER)을 기준으로 오름차순 정렬한다.

Lv.3

카테고리 별 도서 판매량 집계하기

WHERE - 2022년 1월의
GROUP BY, SUM - 카테고리 별 도서 판매량을 합산하고,
SELECT - 카테고리(CATEGORY), 총 판매량(TOTAL_SALES) 리스트를 출력.
ORDER BY - 결과는 카테고리명을 기준으로 오름차순 정렬해주세요.

SELECT 
    b.CATEGORY, 
    SUM(bs.SALES) AS TOTAL_SALES
FROM BOOK_SALES bs
INNER JOIN BOOK b ON b.BOOK_ID = bs.BOOK_ID
WHERE DATE_FORMAT(bs.SALES_DATE, '%Y-%m') = '2022-01'
GROUP BY b.CATEGORY
ORDER BY CATEGORY

즐겨찾기가 가장 많은 식당 정보

FROM - REST_INFO 테이블에서
GROUP BY - 음식종류별로
MAX() - 즐겨찾기수가 가장 많은 식당의
SELECT - 음식 종류, ID, 식당 이름, 즐겨찾기수를 조회
ORDER BY - 결과는 음식 종류를 기준으로 내림차순 정렬해주세요.

INNER JOIN을 사용한 풀이

SELECT r.FOOD_TYPE, REST_ID, REST_NAME, r.FAVORITES
FROM REST_INFO r
INNER JOIN (
    SELECT FOOD_TYPE, MAX(FAVORITES) AS FAVORITES
    FROM REST_INFO
    GROUP BY FOOD_TYPE
) f ON r.FAVORITES = f.FAVORITES AND r.FOOD_TYPE = f.FOOD_TYPE
ORDER BY FOOD_TYPE DESC

WHERE ~ IN 연산자를 사용한 풀이.

SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES
FROM REST_INFO
WHERE (FOOD_TYPE, FAVORITES) IN (
    SELECT FOOD_TYPE, MAX(FAVORITES)
    FROM REST_INFO
    GROUP BY FOOD_TYPE
)
ORDER BY FOOD_TYPE DESC

조건에 맞는 사용자와 총 거래금액 조회하기

FROM - USED_GOODS_BOARD와 USED_GOODS_USER 테이블에서
WHERE - 완료된 중고 거래의
HAVING - 총금액이 70만 원 이상인 사람의
SELECT - 회원 ID, 닉네임, 총거래금액을 조회.
ORDER BY - 결과는 총거래금액을 기준으로 오름차순 정렬해주세요.

SELECT USER_ID, NICKNAME, b.TOTAL_SALES
FROM USED_GOODS_USER u
INNER JOIN (
	SELECT WRITER_ID, SUM(PRICE) AS TOTAL_SALES
	FROM USED_GOODS_BOARD
	WHERE STATUS = 'DONE'
	GROUP BY WRITER_ID
	HAVING SUM(PRICE) >= 700000
) b ON u.USER_ID = b.WRITER_ID
ORDER BY b.TOTAL_SALES

자동차 대여 기록에서 대여중 / 대여 가능 여부 구분하기

SELECT - 자동차 ID와 AVAILABILITY 리스트를 출력
SELECT MAX(IF(조건)) - 2022년 10월 16일에 대여 중인 자동차인 경우 '대여중', 대여 중이지 않은 자동차인 경우 '대여 가능'을 표시하는 컬럼(컬럼명: AVAILABILITY)을 추가, 반납 날짜가 2022년 10월 16일인 경우에도 '대여중'으로 표시
FROM - CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블에서
ORDER BY - 결과는 자동차 ID를 기준으로 내림차순 정렬해주세요.

SELECT 
    CAR_ID,	
    MAX(IF(
    	'2022-10-16' BETWEEN START_DATE AND END_DATE,
        '대여중', 
        '대여 가능'
    )) AS AVAILABILITY
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
GROUP BY CAR_ID
ORDER BY CAR_ID DESC

BETWEEN ~ AND ~ 를 사용해서 2022년 10월 16일이 대여 기간에 포함되어 있다면 '대여중', 아니라면 '대여 가능'으로 값을 넣는다.
그리고 자동차id를 기준으로 여러 텀의 대여 정보가 기록되므로 가장 최신의 텀에 대한 정보만 조회하기위해 GROUP BYMAX()를 사용했다

대여 횟수가 많은 자동차들의 월별 대여 횟수 구하기😰

FROM - CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블에서
WHERE - 대여 시작일(START_DATE)을 기준으로 2022년 8월부터 2022년 10월까지 총 대여 횟수가 5회 이상인 자동차들에 대해서 해당 기간 동안의
SELECT, GROUP BY - 월별 자동차 ID 별 총 대여 횟수(컬럼명: RECORDS) 리스트를 출력하는 SQL문을 작성해주세요.
ORDER BY - 결과는 월을 기준으로 오름차순 정렬하고, 월이 같다면 자동차 ID를 기준으로 내림차순 정렬해주세요.
HAVING - 특정 월의 총 대여 횟수가 0인 경우에는 결과에서 제외해주세요.

SELECT 
    MONTH(START_DATE) AS MONTH, 
    CAR_ID, 
    COUNT(*) AS RECORDS
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE CAR_ID IN (
        SELECT CAR_ID
        FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
        WHERE START_DATE BETWEEN '2022-08-01' AND '2022-10-31'
        GROUP BY CAR_ID
        HAVING COUNT(*) >= 5
    ) AND DATE_FORMAT(START_DATE, '%Y-%m') BETWEEN '2022-08' AND '2022-10'
GROUP BY MONTH, CAR_ID
HAVING RECORDS > 0
ORDER BY MONTH, CAR_ID DESC

문제를 해석하는데 다소 시간이 걸렸던 문제다.

먼저, 2가지 조건을 만족해야 한다. WHERE 1. AND 2.
(조건2가 조건1에 포함되어 있는 게 아닌가? 하고 헷갈렸다.)

  1. CAR_ID의 조건: 2022년 8월부터 2022년 10월까지 총 대여 횟수가 5회 이상인 자동차
CAR_ID IN (
    SELECT CAR_ID
    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
    WHERE START_DATE BETWEEN '2022-08-01' AND '2022-10-31'
    GROUP BY CAR_ID
    HAVING COUNT(*) >= 5
)
  1. START_DATE의 조건: 해당 기간 동안의
DATE_FORMAT(START_DATE, '%Y-%m') BETWEEN '2022-08' AND '2022-10'

그리고 월별 자동차 ID 별 총 대여 횟수(RECORDS)를 구하려면
월과 자동차 ID, 이 2가지로 그룹핑하고 COUNT()로 계산한 RECORDS를 조회한다.

RECORDS가 0인 경우는 제외하고

HAVING RECORDS > 0
-- 또는
HAVING RECORDS <> 0
-- 또는
HAVING RECORDS != 0

주어진 조건대로 정렬하고 마친다.

ORDER BY MONTH, CAR_ID DESC

MONTH() 함수
DATE_FORMAT(날짜, '%c')와 동일한 결과를 표시한다.

profile
검색하고 기록하며 학습하는 백엔드 개발자

0개의 댓글