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

[programmers] String, Date

계란💕 2023. 5. 27. 23:10

조건에 부합하는 중고거래 상태 조회하기-  level 2

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

  Sol)

<hide/>
SELECT BOARD_ID	,WRITER_ID,	TITLE,	PRICE,	
    CASE STATUS
        WHEN 'RESERVED' THEN '예약중'
        WHEN 'DONE' THEN '거래완료'
        WHEN 'SALE' THEN '판매중'
        END STATUS
FROM USED_GOODS_BOARD 
WHERE CREATED_DATE = "2022-10-05"
ORDER BY 1 DESC
  • CASE 문 이용

 


대여 기록이 존재하는 자동차 리스트 구하기 - level  3

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

  Sol)

<hide/>
WITH TMP  AS
(
    SELECT CAR_ID, 
            CASE 
             WHEN MONTH(START_DATE) = 10  THEN 1 
             END "IS_MONTH_OCT"
    FROM CAR_RENTAL_COMPANY_CAR RIGHT JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY USING(CAR_ID)
    WHERE CAR_TYPE = '세단' 
)
SELECT CAR_ID 
FROM TMP
WHERE IS_MONTH_OCT IS NOT NULL
GROUP BY CAR_ID
ORDER BY 1 DESC
  • RIGHT JOIN 
  • DISTINCT를 넣거나 group by를 넣어서 하나의 car_id는 한 번만 출력되도록 한다. 
  •  group by는 서브쿼리가 아니라 본 쿼리에 넣어줘야 에러가 나지 않는다. 
  • IS NOT NULL 을 이용해서 데이터가 있는 경우만 출력되도록 한다.

자동차 평균 대여 기간 구하기 - level 2

출처 - https://school.programmers.co.kr/learn/courses/30/lessons/157342?language=mysql

  Sol)

<hide/>
with TB_DATEDIFF as
(   
    SELECT *, DATEDIFF(END_DATE, START_DATE) + 1  DATEDIFF
    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY 
    ORDER BY  CAR_ID
), TB_AVG as
(
    SELECT  car_id, avg(DATEDIFF) avg
    FROM TB_DATEDIFF 
    group by  car_id
)
SELECT car_id CAR_ID, round(avg, 1) AVERAGE_DURATION
FROM TB_AVG
where avg >= 7
group by car_id having AVERAGE_DURATION >= 7
ORDER BY 2 DESC,car_id DESC 

# AVG가 아닌 반올림된 값으로 정렬해야한다.

 

  • 마지막에 정렬할 때 AVG가 아닌 ROUND()의 결괏값을 기준으로 정렬해야하는 것에 주의한다.

조건에 맞는 사용자 정보 조회하기 - level 3

출처 - https://www.youtube.com/watch?v=ErtObGJ0wWc&t=614s

  Sol)

<hide/>
WITH TMP AS
(
    SELECT USER_ID, NICKNAME, CONCAT(CITY, ' ', STREET_ADDRESS1,' ', STREET_ADDRESS2) 전체주소, 
    CONCAT(SUBSTR(TLNO, 1, 3), '-',
          SUBSTR(TLNO, 4, 4), '-',SUBSTR(TLNO, 8, 4)) 전화번호,
    TLNO,
    COUNT(*) CNT
    FROM USED_GOODS_BOARD JOIN USED_GOODS_USER ON WRITER_ID = USER_ID
    GROUP BY USER_ID
)
SELECT USER_ID, NICKNAME, 전체주소,  전화번호
FROM TMP
WHERE CNT >= 3
ORDER BY 1 DESC
  • CONCAT()을 이용해서 이어 붙인다. 
  • substr(변수명, 1, 3): 1번 인덱스부터 시작해서 3개를 가져온다. 
    • cf)
    • (Java에서는 substring을 이용할 때, 시작 인덱스, 끝 인덱스를 넣는 것과는 다르게 마지막 파라미터에 끝 인덱스가 아닌 끝 인덱스를 넣어준다. )
    • (그리고 인덱스는 0이 아닌 1부터 시작하는 것에 주의한다.)

 


자동차 대여 기록에서 장기/단기 대여 구분하기 - level 1

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

  Sol)

<hide/>
SELECT HISTORY_ID, CAR_ID, 
DATE_FORMAT(START_DATE, '%Y-%m-%d') START_DATE,
DATE_FORMAT(END_DATE, '%Y-%m-%d') END_DATE,
CASE
    WHEN DATEDIFF(END_DATE, START_DATE) + 1 >= 30 THEN '장기 대여'
    ELSE '단기 대여'
    END 'RENT_TYPE'
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY 
WHERE 
YEAR(START_DATE) = 2022 AND
MONTH(START_DATE) = 9
ORDER BY HISTORY_ID DESC
  • 주의할 점은 대여 기간은 시작일, 끝일을 포함해야한다는 점이다. 
    따라서 datediff는 차이  + 1을 해줘야한다. 
  • datediff 는 end_date - start_date  + 1로 설정한다. 
  • date_format 을 이용해서 포맷을 바꿔준다.

 

 


취소되지 않은 진료 예약 조회하기 - level  4

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

  Sol)

<hide/>
SELECT APNT_NO,	PT_NAME, PT_NO,	A.MCDP_CD,	DR_NAME, APNT_YMD
FROM PATIENT JOIN APPOINTMENT A USING (PT_NO)
                JOIN DOCTOR ON DR_ID = MDDR_ID
WHERE YEAR(APNT_YMD) = 2022 AND MONTH(APNT_YMD) = 4  AND  DAY(APNT_YMD) = 13
 AND APNT_CNCL_YN = 'N' 
ORDER BY APNT_YMD
  • 취소 여부가 "N"에 해당하면서 날짜 조건에 맞는 데이터만 가져온다. 

 


조건별로 분류하여 주문 상태 출력하기 - level  3

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

  Sol)

<hide/>
SELECT ORDER_ID, PRODUCT_ID,
DATE_FORMAT(OUT_DATE, "%Y-%m-%d") OUT_DATE,
    CASE 
    WHEN OUT_DATE <= "2022-05-01" THEN "출고완료"
    WHEN OUT_DATE >  "2022-05-01" THEN "출고대기"
    ELSE "출고미정"
    END "출고여부"
FROM FOOD_ORDER 
ORDER BY ORDER_ID
  • CASE문을 이용해서 날짜에 따라 출고 상태를 출력한다. 

 


자동차 대여 기록 별 대여 금액 구하기 - level  4

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

  Sol)

<hide/>
WITH TB_DATEDIFF  AS
(
    SELECT *, DATEDIFF(END_DATE, START_DATE) + 1 DATEDIFF
    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY JOIN CAR_RENTAL_COMPANY_CAR  USING (CAR_ID)
    WHERE CAR_TYPE = '트럭'
)
SELECT HISTORY_ID, 
    CASE 
        WHEN  DATEDIFF >= 90 THEN  ROUND(DAILY_FEE *  (1 - 0.15) * DATEDIFF , 0)
        WHEN  DATEDIFF >= 30 THEN  ROUND( DAILY_FEE *  (1 - 0.08) * DATEDIFF,0)
        WHEN  DATEDIFF >= 7  THEN  ROUND(DAILY_FEE *  (1 - 0.05) * DATEDIFF, 0)
    ELSE DAILY_FEE * DATEDIFF
    END AS FEE
FROM  TB_DATEDIFF
GROUP BY 1
ORDER BY  2 DESC, 1 DESC
  • 세 테이블 중 한 테이블은 JOIN 에 사용하지 않고 CASE문에 직접 데이터를 넣어줬다. 
  • 문제의 예시와 테스트 케이의 테이블을 출력해보면 다르게 할인율이 다르다. 그래서 SELECT * FROM PLAN 을 한 다음에  할인율을 확인한 다음에 그에 맞춰서 CASE 문에 할인율을 넣어줬다. 
  • 그런데 만약, 위 경우와 다르게 데이터가 복잡한 경우에는 위의  duration_type과 할인율을 매치하는 방법을 생각해봐야할 것 같다. 

 


조회수가 가장 많은 중고 거래 게시판의 첨부 파일 조회하기 - level 3

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

  Sol)

<hide/>
SELECT concat('/home/grep/src/',board_id, '/' , FILE_ID, FILE_NAME, FILE_EXT) FILE_PATH
FROM USED_GOODS_FILE
where board_id = (
    SELECT BOARD_ID
    FROM USED_GOODS_BOARD join USED_GOODS_FILE using(BOARD_ID)
    group by BOARD_ID
    order by VIEWS desc
    LIMIT 1
) 
order by 1 desc
  • CONCAT() 을 이용해서 이어 붙인다. 
  • 조횟수가 가장 높은 게시물은 order by, limit를 이용해서 가져온다. 또는 max()를 이용해서 가져올 수도 있다. 

 


특정 옵션이 포함된 자동차 리스트 구하기 - level  1

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

  Sol)

<hide/>
SELECT *
FROM CAR_RENTAL_COMPANY_CAR 
WHERE OPTIONS LIKE('%네비게이션%')
ORDER BY 1 DESC
  • LIKE()를 이용해서 네비게이션이 포함된 차를 가져온다. 

 


루시에 엘라 찾기- level 2

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

  Sol)

<hide/>
SELECT ANIMAL_ID, NAME, SEX_UPON_INTAKE
FROM ANIMAL_INS 
WHERE NAME IN ('Lucy','Ella','Pickle', 'Rogan', 'Sabrina', 'Mitty')
ORDER BY 1
  • NAME이 해당 리스트에 있는지 IN()으로 조건을 넣어준다. 

 


이름에 el이 들어가는 동물 찾기- level  2

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

  Sol)

<hide/>
SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS 
WHERE NAME LIKE('%EL%') AND ANIMAL_TYPE = 'Dog'
ORDER BY NAME
  • LIKE()

 


중성화 여부 파악하기 - level 2

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

  Sol)

<hide/>
SELECT ANIMAL_ID, NAME,
CASE
    WHEN SEX_UPON_INTAKE LIKE('%Neutered%') OR SEX_UPON_INTAKE LIKE('%Spayed%') THEN "O"
    ELSE "X"
    END AS "중성화"
FROM ANIMAL_INS 
ORDER BY ANIMAL_ID
  • "spayed" 포함 여부에 따라 중성화 여부를 판단하고 case 문으로 나눈다. 

오랜 기간 보호한 동물 (2) - level 3

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

  Sol)

<hide/>
WITH TMP AS
(
    SELECT OUTS.ANIMAL_ID OUT_ID, OUTS.NAME OUT_NAME,  INS.DATETIME IN_DT, OUTS.DATETIME OUT_DT, OUTS.DATETIME - INS.DATETIME DIFF
    FROM ANIMAL_INS INS RIGHT JOIN ANIMAL_OUTS OUTS USING (ANIMAL_ID)
    WHERE OUTS.ANIMAL_ID IS NOT NULL
)
SELECT OUT_ID, OUT_NAME
FROM TMP
ORDER BY DIFF DESC
LIMIT 2
  • RIGHT JOIN

 


카테고리별 상품 개수 구하기 - level 2

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

  Sol)

<hide/>
SELECT SUBSTR(PRODUCT_CODE, 1, 2) CATEGORY, COUNT(*)
FROM PRODUCT 
GROUP BY CATEGORY
ORDER BY 1
  • SUBSTR()
  • COUNT()

 


DATETIME에서 DATE로 형변환 - level 2

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

  Sol)

<hide/>
SELECT ANIMAL_ID, NAME, date_format(DATETIME, '%Y-%m-%d') 날짜
FROM ANIMAL_INS 
order by ANIMAL_ID
  • date_format()  으로 반드시 형변환 해줘야한다.

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

[programmers] JOIN  (0) 2023.05.29
[programmers] SUM, MAX, MIN  (0) 2023.05.25
[programmers] IS NULL  (0) 2023.05.22
[programmers] GROUP BY  (0) 2022.11.25
[leetcode] Day 2. SELECT & Order  (0) 2022.11.24