천천히 빛나는
MySQL : GROUP BY 문 고득점 Kit 본문
프로그래머스 SQL 고득점 Kit의 GROUP BY 문제입니다.
https://school.programmers.co.kr/learn/challenges?tab=sql_practice_kit
1. 조건에 맞는 사용자와 총 거래금액 조회하기
SELECT USER_ID, NICKNAME, SUM(PRICE) AS TOTAL_SALES
FROM USED_GOODS_BOARD, USED_GOODS_USER
WHERE USER_ID = WRITER_ID AND STATUS = 'DONE'
GROUP BY USER_ID
HAVING SUM(PRICE) >= 700000
ORDER BY TOTAL_SALES;
FROM → WHERE절 → GROUP BY → HAVING → SELECT → ORDER BY 순서인 것을 고려해서 WHERE과 HAVING을 설정해야 한다.
2. 즐겨찾기가 가장 많은 식당 정보 출력하기
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;
서브에서 GROUP BY를 해주는 문제였다
3. 저자 별 카테고리 별 매출액 집계하기
SELECT B.AUTHOR_ID, W.AUTHOR_NAME, B.CATEGORY, SUM(B.PRICE * BS.SALES) AS TOTAL_SALES
FROM BOOK AS B, AUTHOR AS W, BOOK_SALES AS BS
WHERE B.AUTHOR_ID = W.AUTHOR_ID AND B.BOOK_ID = BS.BOOK_ID AND YEAR(BS.SALES_DATE) = 2022 AND MONTH(BS.SALES_DATE)=1
GROUP BY AUTHOR_ID, CATEGORY
ORDER BY AUTHOR_ID, CATEGORY DESC;
SUM을 이용해서 그룹핑 된 값들의 곱의 합계를 구해야한다
4. 성분으로 구분한 아이스크림 총 주문량
SELECT INGREDIENT_TYPE, SUM(TOTAL_ORDER) AS TOTAL_ORDER
FROM FIRST_HALF, ICECREAM_INFO
WHERE FIRST_HALF.FLAVOR = ICECREAM_INFO.FLAVOR
GROUP BY INGREDIENT_TYPE;
GROUP BY의 기본 문제였다
5. 자동차 대여 기록에서 대여중 / 대여 가능 여부 구분하기
SELECT CAR_ID, IF(('2022-10-16' <= MAX(END_DATE)), '대여중', '대여 가능') AS AVAILABILITY
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE START_DATE <= '2022-10-16'
GROUP BY CAR_ID
ORDER BY CAR_ID DESC;
if (조건문, 참일 때 반환하는 값, 거짓일 때 반환하는 값) 을 사용하였다
CASE WHEN CAR_ID IN (SELECT CAR_ID
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE '2022-10-16' BETWEEN START_DATE AND END_DATE)
THEN '대여중'
ELSE '대여 가능'
END AS 'AVAILABILITY'
CASE WHEN 조건식 THEN 반환식
WHNE 조건식 THEN 반환식
ELSE 만족하지 않을경우
END
와 같은 형식의 CASE WHEN을 사용해도 된다.
CASE WHEN과 GROUP BY를 같이 썼을 때, 하나라도 대여 중이라면 모두 대여 중으로 기록이 되는 것이다. 하나도 대여 중이라고 판단되는게 없으면 대여 가능이 된다.
https://weaver9651.github.io/mysql/2021/03/14/mysql-case-having.html
6. 자동차 종류 별 특정 옵션이 포함된 자동차 수 구하기
SELECT CAR_TYPE, COUNT(*) AS CARS
FROM CAR_RENTAL_COMPANY_CAR
WHERE OPTIONS LIKE '%통풍시트%' OR OPTIONS LIKE '%열선시트%' OR OPTIONS LIKE '%가죽시트%'
GROUP BY CAR_TYPE
ORDER BY CAR_TYPE;
LIKE를 이용해서 쉽게 구현할 수 있다
7. 대여 횟수가 많은 자동차들의 월별 대여 횟수 구하기
SELECT MONTH(START_DATE) AS MONTH, CAR_ID, COUNT(*) AS RECORDS
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE START_DATE BETWEEN '2022-08-01' AND '2022-10-31' AND
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)
GROUP BY MONTH, CAR_ID
order by MONTH, CAR_ID desc
메인 쿼리에 날짜 조건문을 붙여야 하는데 서브에만 붙여서 오류가 많이 났따. 서브에만 붙이면 해당 날짜 외에도 COUNT가 된다. 그러므로 메인쿼리를 꼭 신경써야 한다.
8. 진료과별 총 예약 횟수 출력하기
SELECT MCDP_CD AS '진료과코드', COUNT(*) AS '5월예약건수'
FROM APPOINTMENT
WHERE YEAR(APNT_YMD) = 2022 AND MONTH(APNT_YMD) = 5
GROUP BY MCDP_CD
ORDER BY COUNT(*), MCDP_CD;
GROUP BY 기본 문제이다
9. 카테고리 별 도서 판매량 집계하기
SELECT CATEGORY, SUM(SALES) AS TOTAL_SALES
FROM BOOK, BOOK_SALES
WHERE YEAR(SALES_DATE) = 2022 AND MONTH(SALES_DATE)=1 AND BOOK.BOOK_ID = BOOK_SALES.BOOK_ID
GROUP BY CATEGORY
ORDER BY CATEGORY;
GROUP BY는 ~~별 과 같은 문장이 나올 때 사용하면 된다
10. 식품분류별 가장 비싼 식품의 정보 조회하기
SELECT CATEGORY, PRICE AS MAX_PRICE, PRODUCT_NAME
FROM FOOD_PRODUCT
WHERE (CATEGORY, PRICE) IN (SELECT CATEGORY, MAX(PRICE)
FROM FOOD_PRODUCT
GROUP BY CATEGORY)
AND CATEGORY IN ('과자', '국', '김치', '식용유')
ORDER BY PRICE DESC;
내부쿼리에 GROUP BY를 사용해야 한다
11. 고양이와 개는 몇 마리 있을까
SELECT ANIMAL_TYPE, COUNT(*) AS count
FROM ANIMAL_INS
GROUP BY ANIMAL_TYPE
ORDER BY ANIMAL_TYPE;
고양이 먼저 하려면 오름차순으로 하면 된다. (CAT, DOG)
12. 동명 동물 수 찾기
SELECT NAME, COUNT(*) AS COUNT
FROM ANIMAL_INS
WHERE NAME IS NOT NULL
GROUP BY NAME
HAVING COUNT >= 2
ORDER BY NAME;
IS NOT NULL : NULL 값은 제외
13. 년, 월, 성별 별 상품 구매 회원 수 구하기
SELECT YEAR(SALES_DATE) AS YEAR, MONTH(SALES_DATE) AS MONTH, USER_INFO.GENDER, COUNT(DISTINCT USER_INFO.USER_ID) AS USERS
FROM USER_INFO, ONLINE_SALE
WHERE USER_INFO.USER_ID = ONLINE_SALE.USER_ID AND GENDER IS NOT NULL
GROUP BY YEAR, MONTH, GENDER
ORDER BY YEAR, MONTH, GENDER;
DISTINCT 함수로 중복을 제거해야 한다
14. 입양 시각 구하기 (1)
SELECT HOUR(DATETIME) AS HOUR, COUNT(*) AS COUNT
FROM ANIMAL_OUTS
WHERE DATE_FORMAT(DATETIME, '%H:%i') BETWEEN '09:00' AND '19:59'
GROUP BY HOUR
ORDER BY HOUR;
BETWEEN 없이 하면 HOUR 그대로 이용할 수도 있다
15. 입양 시각 구하기 (2)
없는 시간까지 통계를 내서 만들어주어야 하는 문제였다. 문제 풀이 전에 변수 선언하는 법을 알아야 한다
SET @sum := 0; // 변수 선언
SET @변수이름 := 값;을 이용해서 변수를 선언해줄 수 있다. 지역변수가 된다.
SET @HOUR = -1;
SELECT (@HOUR := @HOUR +1) AS HOUR
FROM ANIMAL_OUTS
WHERE @HOUR < 23;
@HOUR 값에 1씩 증가시키면서 SELECT 문을 실행하게 된다. WHERE 조건을 통해 23까지만 출력을 하게 된다.
SET @HOUR := -1; # 변수선언
SELECT (@HOUR := @HOUR +1) AS HOUR,
(SELECT COUNT(*)
FROM ANIMAL_OUTS
WHERE HOUR(DATETIME) = @HOUR) AS COUNT
FROM ANIMAL_OUTS
WHERE @HOUR < 23;
변수 선언에 대해 알고 있어야지만 풀 수 있는 문제였다.
왜 -1로 시작하고 <23이 되는지는 FROM → WHERE절 → GROUP BY → HAVING → SELECT → ORDER BY 를 안다면 이해할 수 있다.
16. 가격대 별 상품 개수 구하기
SELECT FLOOR(PRICE/10000)*10000 AS PRICE_GROUP, COUNT(*) AS PRODUCTS
FROM PRODUCT
GROUP BY FLOOR(PRICE/10000)
ORDER BY PRICE_GROUP;
나는 직접 바꿔주는 식을 썼는데 TRUNCATE(PRICE, -4)를 사용해도 됐다. TRUNCATE(숫자, 버릴자리수) 이다.
17. 언어별 개발자 분류하기
SELECT
GRADE, ID, EMAIL
FROM (
SELECT
CASE
WHEN
EXISTS (SELECT * FROM SKILLCODES WHERE NAME = 'PYTHON' AND CODE & DEVELOPERS.SKILL_CODE > 0)
AND EXISTS (SELECT * FROM SKILLCODES WHERE CATEGORY = 'Front End' AND CODE & DEVELOPERS.SKILL_CODE > 0)
THEN 'A'
WHEN
EXISTS (SELECT * FROM SKILLCODES WHERE NAME = 'C#' AND CODE & DEVELOPERS.SKILL_CODE > 0)
THEN 'B'
WHEN
EXISTS (SELECT * FROM SKILLCODES WHERE CATEGORY = 'Front End' AND CODE & DEVELOPERS.SKILL_CODE > 0)
THEN 'C'
END AS GRADE, ID, EMAIL
FROM
DEVELOPERS
) AS subquery
WHERE GRADE IS NOT NULL
ORDER BY GRADE, ID;
WHERE에서 FILTER 해줄라면 순서 고려해서 테이블 하나 만들어주고 해야 된다.
'STUDY > MYSQL' 카테고리의 다른 글
MySQL : JOIN 연산 + 기본 예제 (0) | 2023.10.21 |
---|---|
MySQL : IS NULL 문 고득점 Kit (0) | 2023.10.21 |
MySQL : SUM, MAX, MIN 문 고득점 Kit (1) | 2023.10.20 |
MySQL : SELECT 문 고득점 Kit (1) | 2023.10.20 |
MySQL : SELECT 문 + 기본 예제 (2) (1) | 2023.10.20 |