컴퓨터 과학/[프로그래머스 & Leet Code] MySQL 문제 풀이

[programmers] GROUP BY

계란💕 2022. 11. 25. 01:41

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

출처 - https://school.programmers.co.kr/learn/courses/30/lessons/132202

  • GROUP BY, WHERE 절을 이용한다.

  Sol) 

<hide/>
SELECT MCDP_CD '진료과코드', COUNT(*) '5월예약건수'
FROM APPOINTMENT
WHERE YEAR(APNT_YMD) = 2022 AND MONTH(APNT_YMD) = 5
GROUP BY MCDP_CD
ORDER BY 2, 1

 


식품 분류별 가장 비싼 식품의 정보 조회하기 - level 4

  출처 - https://school.programmers.co.kr/learn/courses/30/lessons/131116

  cf) 정답
# 식용 마저유: 8950
# 김치 배추김치: 19000
# 국 김치찌개: 2900
# 과자 허니버터칩: 1950

 

  Sol 1) CTE 방식 - FROM 서브 쿼리와 같음

  • A: 카테고리별 최대 금액, 상품 ID 정보를 담고 있다. 
  • B: 전체 테이블이며 여기에서 상품 이름을 조회해야한다. 
  • A의 최대 금액(M)과 B의 상품 금액이 같은 것만 조회해야한다. 
<hide/>
WITH A AS
(
    SELECT PRODUCT_ID, CATEGORY, MAX(PRICE) M
    FROM FOOD_PRODUCT  
    GROUP BY CATEGORY 
 )
SELECT A.CATEGORY, M, B.PRODUCT_NAME
FROM A JOIN FOOD_PRODUCT B USING (CATEGORY)
WHERE M = PRICE
    AND A.CATEGORY IN ("과자", "국", "김치", "식용유")   
GROUP BY CATEGORY  
ORDER BY 2 DESC

 

 

  Sol 2) WHERE 절 서브 쿼리

  •  
<hide/>
SELECT CATEGORY, MAX(PRICE) AS MAX_PRICE, PRODUCT_NAME
FROM FOOD_PRODUCT F
WHERE CATEGORY IN ('식용유', '김치', '국','과자')
    AND PRICE  = (
        SELECT MAX(PRICE)
        FROM FOOD_PRODUCT
        WHERE CATEGORY = F.CATEGORY
        GROUP BY CATEGORY
    )
GROUP BY 1
ORDER BY 2 DESC

 

 

  Sol 3) WHERE 절 서브 쿼리

<hide/>
SELECT CATEGORY, PRICE AS MAX_PRICE, PRODUCT_NAME
FROM FOOD_PRODUCT 
WHERE CATEGORY IN ('식용유', '김치', '국','과자')
    AND PRICE IN (
        SELECT MAX(PRICE)
        FROM FOOD_PRODUCT
        GROUP BY CATEGORY
        )
GROUP BY 1
ORDER BY PRICE DESC

 

  • 아래와 같이 PRICE IN() 으로 비교를 하고 내부 쿼리에 CATEGORY를 비교하지 않더라도 통과
  • 카테고리를 비교하지 않았는데  어떻게 맞는지 모르겠다
    • 프로그래머스는 테스트 케이스가 하나인데 row 들이 중복되지 않아서 문제 없도록 구성되어 있다.
    • 정확하게 따지면 price 를 등호로 비교하고 where 절로 비교하는 것이 정확하다. 
  • IN() 안에는 카테고리별 최대 금액이 모두 들어가 있다. 

 

  • Ex) 카테고리 비교하지 않을 때 문제점 
    • 만약 식용유, 김치 가격이 이렇게 구성된다면?
      • 식용유: 4500 5000
      • 김치:  4000  4500
      • 이라고 하면 4500원 짜리 식용유는 김치 MAX 와 같다. 
      • 이런 식으로 금액이 다른 카테고리의 MAX 값과 겹치는 경우는 아래 쿼리가  오답이 될 수 있다.
        • 프로그래머스의 테스트 케이스 테이블을 보면 네 개의  max 집합 = { 1950, 2900, 19000,  8950} 인데 
        • a) 김치 중 max 아닌 값: { 16950, 17000, 17500} 
        • b) 식용유  중 max 아닌 값  : {4880, 5950, 7200}
        • c ) 국  중 max 아닌 값  : { 2400, 2450, 2700}
        • d) 과자  중 max 아닌 값 : {1500, 1800, 1900}
        • a, b, c, d 중에서 max 집합에 속하는 값이 없기 떄문에 테스트를 통과한거 아닌가?
        • 다시 말해서, {a, b, c, d } 중에서 max 집합과 교집합이 있는 테스트 케이스가 나오면 오답일 수도 있을 것 같다. 
        • 왜냐하면 카테고리를 비교하지 않기 때문

 


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

출처 -  https://school.programmers.co.kr/learn/courses/30/lessons/131123

 

  Sol ) 

  • 가장 먼저 MAP 처럼 {음식타입, 즐겨찾기 최댓값} 만으로 테이블을 만든다. 
  • 그리고 원래의 테이블과 비교하면서 즐겨찾기 값이 같은 경우만 골라서 출력하도록 WHERE 절 조건을 넣어준다. 
<hide/>
WITH MAP AS
(
SELECT FOOD_TYPE, MAX(FAVORITES) 최댓값
FROM REST_INFO 
GROUP BY FOOD_TYPE
)
SELECT R.FOOD_TYPE, R.REST_ID, R.REST_NAME, R.FAVORITES
FROM MAP JOIN REST_INFO  R USING (FOOD_TYPE)
WHERE 최댓값 = FAVORITES
ORDER BY 1 DESC

 


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

출처 - https://school.programmers.co.kr/learn/courses/30/lessons/151139

 

  • GROUP BY CAR_ID, MONTH .. 이런 식으로 만들어 줘야한다. 

 

  Sol) 

  • 대여 기간은 시작일(START_DATE)을 기준으로 한다. 
  • SUB_H: 전체 테이블과 JOIN 하기 위해 만드는 테이블이며 자동차별로 해당 기간에 대여한 횟수를 COUNT 해서 반환한다. 
    • 따라서 이 테이블은 대여 횟수 5 이상인 자동차 ID 정보만을 가져오기 위해서 필요한 테이블이다. 
  • H: 전체 테이블
  • SUB_H 테이블에서 대여 횟수가 5이상인 데이터만 가져온 다음에, H 테이블에서도 기간 조건을 만족하는 데이터를 가져와서 JOIN 한다. 두 개의 테이블에 기간 조건을 공통적으로 넣어줘야한다. 
  • 아래 블로그 내용을 참고해서 조금 변형해서 풀었다. 

 

출처 - https://amyyzzin.tistory.com/411

<hide/>
WITH SUB_H AS(
    SELECT CAR_ID, COUNT(*) 차량별대여횟수
    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY 
    WHERE YEAR(START_DATE) = 2022
        AND MONTH(START_DATE) >= 8
        AND MONTH(START_DATE) <= 10
    GROUP BY 1
)
SELECT MONTH(H.START_DATE), H.CAR_ID,  COUNT(*) RECORDS
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY H JOIN SUB_H USING (CAR_ID)
WHERE 차량별대여횟수 >= 5
    AND YEAR(START_DATE) = 2022
    AND MONTH(START_DATE) >= 8
    AND MONTH(START_DATE) <= 10
GROUP BY 2, 1
ORDER BY 1, 2 DESC

 


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

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

 

 

 Sol) 

  • JOIN해서 각 카테고리에 대한 모든 판매량을 더해준다. 
<hide/>
SELECT CATEGORY, SUM(SALES) TOTAL_SALES
FROM BOOK B JOIN BOOK_SALES BS USING (BOOK_ID)
WHERE YEAR(SALES_DATE) = 2022 
    AND MONTH(SALES_DATE) = 1
GROUP BY CATEGORY 
ORDER BY 1

 


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

출처  - https://school.programmers.co.kr/learn/courses/30/lessons/133026 

 

  Sol)

<hide/>
SELECT INGREDIENT_TYPE , SUM(TOTAL_ORDER) 
FROM FIRST_HALF RIGHT JOIN ICECREAM_INFO ICE USING (FLAVOR)
GROUP BY INGREDIENT_TYPE
  • group by 로 나눠서 주문량의 총합을 구한다. 

 


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

출처 - https://school.programmers.co.kr/learn/courses/30/lessons/151137 

 

  Sol)

<hide/>
SELECT  CAR_TYPE, count(*)
FROM CAR_RENTAL_COMPANY_CAR
WHERE OPTIONS LIKE('%통풍시트%')
    OR OPTIONS LIKE('%열선시트%')
    OR OPTIONS LIKE('%가죽시트%')
GROUP BY CAR_TYPE
ORDER BY 1
  • GROUP BY
  • LIKE() 안에 와일드 카드를 넣어서 조건을 만든다. 

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

출처 - https://school.programmers.co.kr/learn/courses/30/lessons/59040 

 

  Sol)

<hide/>
SELECT ANIMAL_TYPE, COUNT(*)
FROM ANIMAL_INS 
GROUP BY ANIMAL_TYPE
ORDER BY 1

 


동명 동물 수 찾기 - level 2

출처 - https://school.programmers.co.kr/learn/courses/30/lessons/59041 

 

  Sol)

<hide/>
WITH TMP AS
(
    SELECT NAME, COUNT(*) CNT
    FROM ANIMAL_INS 
    WHERE NAME IS NOT NULL
    GROUP BY NAME
)
SELECT  *
FROM TMP
WHERE CNT > 1
ORDER BY 1
  • where절에 is not null을 꼭 추가해야한다. 

 


입양 시각 구하기 (1) - level 2

출처  - https://school.programmers.co.kr/learn/courses/30/lessons/59412

 

  Sol)

<hide/>
WITH TMP AS
(
    SELECT ANIMAL_ID, date_FORMAT(DATETIME, '%H')  HOUR
    FROM ANIMAL_OUTS 
)
SELECT HOUR, COUNT(ANIMAL_ID)
FROM TMP JOIN ANIMAL_OUTS USING (ANIMAL_ID)
WHERE HOUR >= 9 AND HOUR < 20
GROUP BY HOUR
ORDER BY 1
  • 동일한 두 개의 테이블을 조인해서 가져온다. 
  • PK인 ANIMAL_ID를 사용해서 조인한다. 
  • COUNT(ANIMAL_ID)를 해주면 해당하는 시간에 맞는 로우를 카운트한다. 
  • 시간 형식은 DATE_FORMAT()을 사용한다. 

 


가격대 별  상품 개수 구하기 - level 2

출처  - https://school.programmers.co.kr/learn/courses/30/lessons/131530

  Sol)

<hide/>
SELECT  PRICE - PRICE % 10000 PRICE_GROUP, COUNT(*)
FROM PRODUCT
GROUP BY PRICE_GROUP
ORDER BY 1
  • 가격을 의미하는 PRICE에서 10000으로 나눈 나머지를 빼면  PRICE_GROUP를 구할 수 있다. 

 


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

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

  Sol)

<hide/>
WITH TMP AS
(
    SELECT *, SUM(PRICE) TOTAL_SALES
    FROM USED_GOODS_BOARD JOIN USED_GOODS_USER ON WRITER_ID = USER_ID
    WHERE STATUS = "DONE"
    GROUP BY USER_ID
)
SELECT USER_ID, NICKNAME, TOTAL_SALES
FROM TMP 
WHERE TOTAL_SALES >= 700000
ORDER BY 3
  • 임시 쿼리 안에 총 거래 금액을 구하고  WHERE 절 조건으로 DONE 상태인 로우만 가져오도록 쿼리를 짠다. 

 


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

출처 - https://school.programmers.co.kr/learn/courses/30/lessons/157340  

  Sol)

<hide/>
WITH TMP AS
(
    SELECT CAR_ID, 
       CASE
         WHEN START_DATE <= '2022-10-16' AND '2022-10-16' <= END_DATE THEN 1
         ELSE 0
         END AVAILABILITY_N
    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY 
)
SELECT CAR_ID, 
    CASE
        WHEN SUM(AVAILABILITY_N) = 1 THEN '대여중'
        ELSE '대여 가능'
        END 
FROM TMP
GROUP BY CAR_ID
ORDER BY CAR_ID DESC
  • tmp: 대여중인 car에 대해서만 1을 넣어주고 다른 행은 모두 0으로 넣어준다. 
  • 본 쿼리에서는 GROUP BY를 이용해서 위에 숫자로 표현한 값을 모두 더해주고 더한 값이 1인 경우는 "대여중", 그 외의 경우는 "대여 가능"으로 표시한다. 

저자 별 카테고리 별 매출액 집계하기  - level 4

출처 - https://school.programmers.co.kr/learn/courses/30/lessons/144856

  Sol)

<hide/>
SELECT AUTHOR_ID, AUTHOR_NAME, CATEGORY,
SUM(SALES * PRICE) TOTAL_SALES
FROM AUTHOR JOIN BOOK USING (AUTHOR_ID)
            JOIN BOOK_SALES USING (BOOK_ID) 
WHERE YEAR(SALES_DATE) = 2022 AND MONTH(SALES_DATE) = 1
GROUP BY AUTHOR_ID, CATEGORY
ORDER BY 1, 3 DESC
  • GROUP BY 조건을 이중으로 넣는다. 
  • WHERE 절에도 연도, 월에 대한 조건을 반드시 넣어야한다. 

년, 월, 성별 별 상품 구매 회원 수 구하기-  level 4

출처 - https://school.programmers.co.kr/learn/courses/30/lessons/131532  

  Sol)

  • DISTINCT를 꼭 넣어줘야한다. 넣지 않으면 같은 USER_ID가 중복되서 카운트되기 때문에 주의한다. 
  • GROUP BY로 세 번 중첩해서 그룹을 나눠준다. 
<hide/>
SELECT YEAR(SALES_DATE) YEAR, MONTH(SALES_DATE) MONTH, GENDER
, COUNT(DISTINCT USER_ID) USERS
FROM ONLINE_SALE JOIN USER_INFO USING (USER_ID)
WHERE GENDER IS NOT NULL
GROUP BY YEAR(SALES_DATE), MONTH(SALES_DATE), GENDER
ORDER BY 1, 2, 3

 


입양 시각 구하기 (2) -  level 4

출처 - https://school.programmers.co.kr/learn/courses/30/lessons/59413  

  Sol)

<hide/>
SET @HOUR = -1;
SELECT @HOUR := @HOUR + 1, 
    (SELECT COUNT(*)
     FROM ANIMAL_OUTS
     WHERE  @HOUR = HOUR(DATETIME)
    )
FROM ANIMAL_OUTS
WHERE @HOUR < 23
  • 행 번호를 생성해야한다. 
  • set @hour = - 1;   변수를 생성한다.  
  • SELECT @hour := @hour + 1    FROM ANIMAL_OUTS     WHERE @hour < 23
    • 서브쿼리를 이용해서 외부 쿼리와 시간이 같은 경우에 대해서 COUNT() 해준다. 

'컴퓨터 과학 > [프로그래머스 & Leet Code] MySQL 문제 풀이' 카테고리의 다른 글

[programmers] String, Date  (0) 2023.05.27
[programmers] SUM, MAX, MIN  (0) 2023.05.25
[programmers] IS NULL  (0) 2023.05.22
[leetcode] Day 2. SELECT & Order  (0) 2022.11.24
[leetcode] SELECT  (0) 2022.09.28