본문 바로가기

코딩테스트

[MySQL] 프로그래머스 SQL 고득점 Kit - JOIN

 

어려운 JOIN 연습

https://school.programmers.co.kr/learn/courses/30/parts/17046

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

 


1. 특정 기간동안 대여 가능한 자동차들의 대여비용 구하기

SELECT DISTINCT C.CAR_ID, C.CAR_TYPE, FLOOR(30*DAILY_FEE*(1 - DISCOUNT_RATE/100)) AS FEE
    FROM CAR_RENTAL_COMPANY_CAR AS C
    JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY AS H
      ON C.CAR_ID = H.CAR_ID 
    JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN AS D
      ON C.CAR_TYPE = D.CAR_TYPE AND
         D.DURATION_TYPE = '30일 이상'
    WHERE C.CAR_TYPE IN ('세단', 'SUV') 
          AND C.CAR_ID NOT IN (SELECT CAR_ID 
                                 FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
                                WHERE NOT (END_DATE < '2022-11-01' OR 
                                           '2022-11-30' < START_DATE))
    HAVING FEE BETWEEN 500000 AND 2000000-1
    ORDER BY 3 DESC, 2, 1 DESC;
  • 개인적으로 딱 깔끔하다고 느낀 풀이이다.
  • ON 절에서 AND 또는 OR로 조건을 추가할 수 있다.
  • MySQL에서 날짜 비교시에는 작은 따옴표 ' ' 로 묶어준다.
  • 계산의 반복을 피하기 위해 되도록 SELECT 절에 계산 명시 후 HAVING 절에 해당 데이터를 이용하는 것도 좋을 것 같다.

 

2. 없어진 기록 찾기

-- 코드를 입력하세요
SELECT AO.ANIMAL_ID, AO.NAME
FROM ANIMAL_OUTS AO LEFT JOIN ANIMAL_INS AI ON AO.ANIMAL_ID=AI.ANIMAL_ID
WHERE AI.ANIMAL_ID IS NULL
ORDER BY 1, 2;
  • LEFT JOIN 이 생각 났다! AO를 기준으로 LEFT JOIN을 할 때 AI에 존재하지 않는 데이터는 NULL로 처리해버릴 것이다.

 

 

3. 있었는데요 없었습니다.

-- 코드를 입력하세요
SELECT AO.ANIMAL_ID, AO.NAME
FROM ANIMAL_OUTS AO JOIN ANIMAL_INS AI ON AO.ANIMAL_ID=AI.ANIMAL_ID
WHERE AI.DATETIME > AO.DATETIME
ORDER BY AI.DATETIME;

 

 

4. 오랜 기간 보호한 동물

-- 코드를 입력하세요
SELECT AI.NAME, AI.DATETIME
FROM ANIMAL_INS AI LEFT JOIN ANIMAL_OUTS AO ON AO.ANIMAL_ID=AI.ANIMAL_ID
WHERE AO.ANIMAL_ID IS NULL
ORDER BY AI.DATETIME
LIMIT 3;
  • DATETIME ASC -> 오래된 순, DESC -> 최신순

 

5. 보호소에서 중성화한 동물

SELECT AI.ANIMAL_ID, AI.ANIMAL_TYPE, AI.NAME
FROM ANIMAL_INS AI JOIN ANIMAL_OUTS AO ON AO.ANIMAL_ID=AI.ANIMAL_ID
WHERE AI.SEX_UPON_INTAKE LIKE "Intact%" and (AO.SEX_UPON_OUTCOME LIKE "Spayed%" OR AO.SEX_UPON_OUTCOME LIKE "Neutered%")
ORDER BY 1, 2, 3;
  • 컬럼 도메인에 대해 좀 더 자세하게 설명해줬으면....
  • LIKE ~ OR ~ 로 LIKE를 여러개  비교하는 것은 안된다.

 

6. 상품 별 오프라인 매출 구하기

-- 코드를 입력하세요
SELECT P.PRODUCT_CODE, SUM(OS.SALES_AMOUNT*P.PRICE) AS SALES
FROM PRODUCT P JOIN OFFLINE_SALE OS ON P.PRODUCT_ID=OS.PRODUCT_ID
GROUP BY OS.PRODUCT_ID
ORDER BY 2 DESC, 1;

 

 

7. 상품을 구매한 회원 비율 구하기

SELECT YEAR(O.SALES_DATE) AS YEAR, MONTH(O.SALES_DATE) AS MONTH,
    COUNT( DISTINCT O.USER_ID) AS PURCHASED_USERS,
    ROUND((COUNT(DISTINCT O.USER_ID)/(SELECT COUNT(*) FROM USER_INFO WHERE YEAR(JOINED) = 2021)),1) AS PURCHASED_RATIO
FROM ONLINE_SALE O
WHERE O.USER_ID IN (SELECT USER_ID FROM USER_INFO WHERE YEAR(JOINED) = 2021)
GROUP BY YEAR, MONTH
ORDER BY YEAR, MONTH;
  • 서브쿼리를 활용한 문제. SELECT 절 안에서 서브 쿼리를 활용했다.

 

8. 5월 식품들의 총매출 조회하기

-- 코드를 입력하세요
SELECT FP.PRODUCT_ID, FP.PRODUCT_NAME, SUM(FP.PRICE*FO.AMOUNT) AS TOTAL_SALES
FROM FOOD_PRODUCT FP JOIN FOOD_ORDER FO ON FP.PRODUCT_ID=FO.PRODUCT_ID
WHERE FO.PRODUCE_DATE LIKE "2022-05%"
GROUP BY FO.PRODUCT_ID
ORDER BY 3 DESC, 1;
  • FOOD_ORDER에 동일한 PRODUCT_ID를 가진 데이터가 있을 수 있음!

 

9. 주문량이 많은 아이스크림 조회하기

SELECT
    F.FLAVOR
FROM
    FIRST_HALF F INNER JOIN JULY J
    ON F.FLAVOR = J.FLAVOR
GROUP BY
    F.FLAVOR
ORDER BY
    SUM(F.TOTAL_ORDER + J.TOTAL_ORDER) DESC
LIMIT 3;
  • FLAVOR로 INNER JOIN하니 더 쉬움. 
  • 처음에는 J.TOTAL_ORDER에만 SUM을 적용했는데 값이 제대로 나오지 않음. TOTAL_ORDER의 총합으로 구해도 된다.

 

 

10. 조건에 맞는 도서와 저자 리스트 출력하기

-- 코드를 입력하세요
SELECT B.BOOK_ID, A.AUTHOR_NAME, DATE_FORMAT(B.PUBLISHED_DATE, "%Y-%m-%d") AS PUBLISHED_DATE
FROM BOOK B JOIN AUTHOR A ON B.AUTHOR_ID=A.AUTHOR_ID
WHERE B.CATEGORY="경제"
ORDER BY 3;

 

 

11. 그룹별 조건에 맞는 식당 목록 출력하기

-- 코드를 입력하세요
SELECT M.MEMBER_NAME, R.REVIEW_TEXT, DATE_FORMAT(R.REVIEW_DATE, "%Y-%m-%d") AS REVIEW_DATE
FROM MEMBER_PROFILE M JOIN REST_REVIEW R ON M.MEMBER_ID=R.MEMBER_ID
WHERE R.MEMBER_ID = (SELECT MEMBER_ID FROM REST_REVIEW GROUP BY MEMBER_ID
ORDER BY COUNT(*) DESC
LIMIT 1)
ORDER BY R.REVIEW_DATE, 2;
  • 서브쿼리에서 정렬 시 GROUP BY한 값을 기준으로 COUNT(*) 정렬하는 것 주의!

 

 

12. FrontEnd 개발자 찾기

-- 코드를 작성해주세요
SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPERS
WHERE SKILL_CODE&(SELECT SUM(CODE) FROM SKILLCODES WHERE CATEGORY="Front End") > 0
ORDER BY 1;

 

 

 

 


회고

어느정도 JOIN에 익숙해졌다!

가끔 헷갈리는 것만 제외하면 4까지는 풀 수 있을 것 같다. 5는...문제를 많이 못봐서 모르겠음

 

갑자기 궁금해져서 찾아본 제약 조건 확인 명령어

SHOW CREATE TABLE your_table_name;