본문 바로가기
카테고리 없음

프로그래머스 SQL 고득점 KIT GROUP BY

by 신우탁 2023. 7. 19.

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

lv2, GROUP BY

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

우선 INNER JOIN으로 테이블을 합친 후 문제에서 요구하는 INGREDIENT_TYPE로 TOTAL_ORDER를 집계하기 위해 그룹화를 하였다. 처음에 GROUP BY INGREDIENT_TYPE, TOTAL_ORDER를 실행했을 때는 정답이 안나왔는데 그러면 두개의 칼럼을 기준으로 그룹화하기 때문에 오답이 나온다. 문제의 답으로 INGREDIENT_TYPE를 기준으로 TOTAL_ORDER을 출력해야하므로 그룹화 기준을 INGREDIENT_TYPE만 놓는 것이 맞다.

 

 

 

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

lv2, GROUP 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

WHERE과 HAVING을 헷갈리면 안되는데 두개의 차이점은 WHERE은 그룹화 하기 전의 조건절, HAVING은 그룹화 한 후의 조건절이라는 것이다. 문제에서 차의 옵션 중에 가죽시트, 통풍시트, 열선시트가 포함되어있어야 한다고 했기 때문에 LIKE을 사용하였다. 참고로 %을 안붙이면 부분검색이 안된다. 조건절을 만족한 행들을 CAR_TYPE을 기준으로 그룹화 한 후 오름차순으로 정렬하면 된다.

 

 

 

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

lv2, GROUP BY

SELECT MCDP_CD AS 진료과코드, COUNT(*) AS 5월예약건수
FROM APPOINTMENT 
WHERE MONTH(APNT_YMD)=05
GROUP BY 진료과코드
ORDER BY 5월예약건수, 진료과코드

WHERE에서 진료를 5월에 받은 데이터를 뽑아내고 예약건수를 세기 위해 진료과코드를 기준으로 그룹화를 하였다. 

 

 

 

 

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

lv2, GROUP BY

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

고양이와 개를 세는 문제이다. ANIMAL_TYPE을 기준으로 그룹화 한 다음 Cat이 Dog보다 먼저 조회돼야하므로 ANIMAL_TYPE을 기준으로 오름차순 정렬하였다.

 

 

 

동명 동물 수 찾기

lv2, GROUP BY

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

NAME이 없는 행은 무시해야하므로 IS NOT NULL을 사용하였고, NAME을 기준으로 그룹화하였다. HAVING을 통해 그룹화 후의 조건을 걸어주었고 NAME당 COUNT가 2개 이상인 행만 남겼다.

 

 

 

 

입양 시각 구하기(1)

lv2, GROUP BY

SELECT HOUR(DATETIME) HOUR, COUNT(DATETIME) COUNT
FROM ANIMAL_OUTS
GROUP BY HOUR(DATETIME)
HAVING HOUR >= 9 and HOUR <= 19
ORDER BY HOUR

많이 헷갈린 문제였다.

SQL 쿼리 실행순서를 보면 HAVING 다음에 SELECT가 실행된다. 그러나 코드를 보면 HAING에서 SELECT에서 지정한 HOUR을 이미 쓰고있다. 이 부분이 헷갈려서 찾아봤는데 WHERE을 제외한 GROUP BY, HAVING, ORDER BY에서 SELECT에서 지정한 alias를 사용할 수 있다고 한다. 이유는 DBMS가 알아서 최적화를 해준다고 한다. DATETIME의 HOUR 부분만 뽑아서 HOUR을 기준으로 그룹화를 한 후, 조건에 맞는 HOUR들만 COUNT하였다.

 

 

 

가격대 별 상품 개수 구하기

lv2, GROUP BY

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

PRICE를 문제에서 원하는 대로 바꿀 필요가 있었기에 TRUNCATE 함수를 사용했다. TRUNCATE(숫자,n)은 숫자의 소수점 n번째 이하로는 버린다는 의미이다. 그리고 SELECT에서 지정한 alias인 PRICE_GROUP를 GROUP, ORDER에서 사용하였다.

 

SELECT TRUNCATE(123.456 ,1) FROM DUAL;
// 123.4
 
SELECT TRUNCATE(123.456 ,2) FROM DUAL;
// 123.45
 
SELECT TRUNCATE(123.456 ,-1) FROM DUAL;
// 120
 
SELECT TRUNCATE(123.456 ,-2) FROM DUAL;
// 100

 

 

 

 

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

lv3, GROUP BY

어려웠던 문제다. 여러 블로그들을 참고했는데 헷갈리는 점이 있었다.

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

해당 코드로 제출을 하면 예시의 답과 똑같이 나오지만 정답처리가 되지 않는다. 이유는 GROUP BY를 하면 출력할 때 REST_ID와 REST_NAME이 FAVORITES가 최대값인 식당의 REST_ID와 REST_NAME이 아닌 쿼리의 맨 위에 있는 값을 가져오게 된다. 문제에서는 FAVORITES가 최대값인 식당의 REST_ID와 REST_NAME이 출력되어야 하므로 올바른 답이 아니지만 우연히 문제의 예시에서는 답과 출력이 일치해 혼란이 생겼었다.

 

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;

 정답 코드이다. 위의 코드와 다른 점은 서브 쿼리를 사용해 FAVORITES가 최대값인 음식점의 REST_ID와 REST_NAME을 테이블에 세팅해두었고 WHERE에서 그 테이블에서 맞는 데이터만 쏙쏙 빼와서 출력하는 방식이다.

 

 

https://school.programmers.co.kr/learn/courses/30/lessons/164668

https://school.programmers.co.kr/learn/courses/30/lessons/144855