본문 바로가기

[공부] SQL

[SQL 코딩테스트] 프로그래머스 String, Date 정답

재밌을 때 진도 쭉쭉 빼기!


자동차 대여 기록에서 장기/단기 대여 구분하기
#DATEDIFF #DATE_FORMAT

 

와... 쓸데없이 짱 헤멘 문제.

DATEDIFF한 결과값에 +1을 해줘야 한다. 질문하기 게시판에 요 내용으로 틀린 사람들이 수두룩...

왜냐하면 오늘 빌려서 오늘 반납한 경우, 두 날짜를 빼면 0이 되지만 대여일은 1일로 계산하기 때문이다.

마찬가지로 오늘 빌려서 내일 반납하면 대여일은 2일이다.

SELECT  history_id, 
        car_id,
        DATE_FORMAT(start_date, '%Y-%m-%d') start_date,
        DATE_FORMAT(end_date, '%Y-%m-%d') end_date,
        IF (DATEDIFF(END_DATE,START_DATE)+1 >= '30', 
            '장기 대여', '단기 대여') AS RENT_TYPE
  FROM  CAR_RENTAL_COMPANY_RENTAL_HISTORY 
 WHERE  DATE_FORMAT(START_DATE, '%Y-%m') = '2022-09'
 ORDER
    BY HISTORY_ID DESC

 

특정 옵션이 포함된 자동차 리스트 구하기
#LIKE
SELECT  *
  FROM  CAR_RENTAL_COMPANY_CAR 
 WHERE  OPTIONS LIKE '%네비게이션%'
 ORDER
    BY  CAR_ID DESC

 

조회수가 가장 많은 중고거래 게시판의 첨부파일 조회하기
#CONCAT #JOIN #WHERE

 

CONCAT을 활용해야 했던 문제. JOIN에 WHERE조건까지 살짝 쫄았지만 침착하게 풀었다.

언제쯤 아 이거 아는데... 함수가 뭐였더라...? 하지 않고 척척 풀 수 있게 될까?

문제풀이 끝내는 3주 뒤에는 그렇게 되길!

SELECT  CONCAT('/home/grep/src/',F.BOARD_ID,
               '/',F.FILE_ID,F.FILE_NAME,F.FILE_EXT) 
               FILE_PATH
  FROM  USED_GOODS_BOARD B
        JOIN USED_GOODS_FILE F
        ON B.BOARD_ID = F.BOARD_ID
 WHERE  B.VIEWS = 
        (SELECT MAX(VIEWS) FROM USED_GOODS_BOARD)
 ORDER
    BY   FILE_ID DESC 
  ;

 

조건에 맞는 사용자 정보 조회하기
# CONCAT_WS #SUBSTRING #SUBSTR #HAVING

 

여전히 헷갈리는 WHERE과 HAVING. 일단은 GROUP BY를 사용해 묶어놓은 열에서 조건을 찾고 싶으면 HAVING이라고 생각해본다.

그래도 이렇게 어려운 문제 혼자 풀었을 때의 짜릿함이란!

SELECT  U.USER_ID, U.NICKNAME, 
        CONCAT_WS(' ', CITY, STREET_ADDRESS1, STREET_ADDRESS2) 전체주소, 
        CONCAT_WS('-',SUBSTR(TLNO,1,3),SUBSTR(TLNO,4,4),SUBSTR(TLNO,8,4)) 전화번호
  FROM  USED_GOODS_BOARD B
        JOIN USED_GOODS_USER U
        ON B.WRITER_ID = U.USER_ID
 GROUP
    BY  USER_ID
HAVING  COUNT(USER_ID) >= 3
 ORDER
    BY  U.USER_ID DESC
        ;

 

자동차 대여 기록 별 대여 금액 구하기
WITH, CASE
⏰ 33:10

 

휴우 이제 이정도는 뚝딱뚝딱 할 수 있게 되었다!

WITH HISTORY AS (
    SELECT HISTORY_ID, 
           CAR_TYPE, 
           DATEDIFF(END_DATE, START_DATE) + 1 AS DURATION,
           CASE WHEN DATEDIFF(END_DATE, START_DATE) + 1 BETWEEN 7 AND 29 THEN '7일 이상'
                WHEN DATEDIFF(END_DATE, START_DATE) + 1 BETWEEN 30 AND 89 THEN '30일 이상'
                WHEN DATEDIFF(END_DATE, START_DATE) + 1 >= 90 THEN '90일 이상'
           END AS DURATION_TYPE,
            START_DATE,END_DATE,
           DAILY_FEE
FROM CAR_RENTAL_COMPANY_CAR
    JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY
    USING (CAR_ID)
WHERE CAR_TYPE = '트럭'
ORDER BY 3
    )

SELECT HISTORY_ID, -- H.CAR_TYPE, DAILY_FEE,DURATION, DISCOUNT_RATE, START_DATE, END_DATE, 
       CASE WHEN DISCOUNT_RATE IS NULL THEN ROUND(DURATION * DAILY_FEE,0)
       ELSE ROUND(DURATION * DAILY_FEE * (100 - DISCOUNT_RATE) / 100,0)
       END AS FEE
FROM HISTORY H
     LEFT JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN P
     ON P.CAR_TYPE = H.CAR_TYPE AND P.DURATION_TYPE = H.DURATION_TYPE
ORDER BY 2 DESC,1 DESC
조건에 부합하는 중고거래 상태 조회하기
#CASE #DATE_FORMAT

 

이제 CASE 구문도 익숙해지는 중!

SELECT  BOARD_ID, WRITER_ID, TITLE, PRICE, 
        CASE WHEN STATUS = 'SALE'
             THEN '판매중'
             WHEN STATUS = 'RESERVED'
             THEN '예약중'
             ELSE '거래완료'
        END AS STATUS
  FROM  USED_GOODS_BOARD 
 WHERE  DATE_FORMAT(CREATED_DATE, '%Y-%m-%d') = '2022-10-05'
 ORDER
    BY  BOARD_ID DESC
  ;

 

조건별로 분류하여 주문상태 출력하기
#DATE #CASE

 

오늘도 어이없는 실수로 한참 고민한 썰 푼다.. (FEAT. 쉼표 빼먹음)

SELECT  ORDER_ID, PRODUCT_ID, 
        DATE_FORMAT(OUT_DATE, '%Y-%m-%d') OUT_DATE,
        CASE WHEN DATEDIFF('2022-05-01',OUT_DATE) >= 0
             THEN '출고완료'
             WHEN DATEDIFF('2022-05-01',OUT_DATE) < 0
             THEN '출고대기'
             WHEN OUT_DATE IS NULL
             THEN '출고미정'
        END 
        출고여부
  FROM  FOOD_ORDER
 ORDER
    BY  ORDER_ID
  ;

친절하게 알려주는 챗GPT

 

대여 기록이 존재하는 자동차 리스트 구하기
#JOIN #AND #DISTINCT
SELECT  DISTINCT C.CAR_ID
  FROM  CAR_RENTAL_COMPANY_CAR C
        JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY H
        ON C.CAR_ID = H.CAR_ID
 WHERE  CAR_TYPE = '세단' AND MONTH(start_date) = 10
 ORDER
    BY  CAR_ID DESC
  ;

 

자동차 평균 대여 기간 구하기
#GROUPBY #HAVING #AVG #ROUND
SELECT  CAR_ID, ROUND(AVG(DATEDIFF(END_DATE,START_DATE)+1),1) AVERAGE_DURATION
  FROM  CAR_RENTAL_COMPANY_RENTAL_HISTORY
 GROUP
    BY  CAR_ID
HAVING  AVG(DATEDIFF(END_DATE,START_DATE)+1) >= 7
 ORDER
    BY  AVERAGE_DURATION DESC, CAR_ID DESC
  ;

 

취소되지 않은 진료 예약 구하기
JOIN
⏰ 10:10

 

이제 이정도는 뚝딱인걸로!

    SELECT A.APNT_NO,
           P.PT_NAME,
           P.PT_NO,
           A.MCDP_CD,
           D.DR_NAME,	
           A.APNT_YMD
    FROM APPOINTMENT A
        LEFT JOIN PATIENT P
        ON A.PT_NO = P.PT_NO
        LEFT JOIN DOCTOR D
        ON A.MDDR_ID = D.DR_ID
    WHERE A.APNT_CNCL_YN = 'N' 
          AND A.MCDP_CD = 'CS'
          AND DATE_FORMAT(A.APNT_YMD, '%Y-%m-%d') = '2022-04-13'
    ORDER BY A.APNT_YMD

 

루시와 엘라 찾기
#IN #WHERE

 

처음에 IN 함수에 따옴표 ' 안 붙여서 오류가 떴고... 한참 헤멜 뻔 했다!

복잡함에 속아 기본을 잊지 말자(?)

SELECT  ANIMAL_ID, NAME, SEX_UPON_INTAKE
  FROM  ANIMAL_INS
 WHERE  NAME IN ('Lucy', 'Ella', 'Pickle', 'Rogan', 'Sabrina', 'Mitty')
 ORDER
    BY  ANIMAL_ID
  ;

 

이름에 el이 들어가는 동물 찾기
#LIKE #AND
SELECT  ANIMAL_ID, NAME
  FROM  ANIMAL_INS
 WHERE  NAME LIKE '%EL%' AND ANIMAL_TYPE = 'DOG'
 ORDER
    BY  NAME
;

 

중성화 여부 파악하기
#CASE

 

지난번에 풀었던 CASE 구문이다! 하고 신나게 풀었다가 END 안써서 틀린 사람~ 그게 나예요~

차차 기본적인 실수는 줄여나가자.

SELECT  ANIMAL_ID, NAME,
        CASE WHEN SEX_UPON_INTAKE LIKE 'Neutered%'
             THEN 'O'
             WHEN SEX_UPON_INTAKE LIKE 'Spayed%'
             THEN 'O'
             ELSE 'X'
        END 중성화
  FROM  ANIMAL_INS
 ORDER
    BY  ANIMAL_ID
  ;

 

오랜 기간 보호한 동물(2)
#JOIN #LIMIT

 

서브쿼리와 RANK를 써야하나..? 한참 끙끙 앓다가 챗GPT한테도 물어보고 이것저것 시도해보는데 1시간을 썼다.

LIMIT을 쓰면 뚝딱이고, ORDER BY에서는 굳이 SELECT에서 안 뽑는 열을 써도 되는데 괜히 JOIN이라고 쫄아서 생각 못하고 있었던 것...

SELECT  I.ANIMAL_ID, I.NAME
  FROM  ANIMAL_INS I
        JOIN ANIMAL_OUTS O 
        ON I.ANIMAL_ID = O.ANIMAL_ID
 ORDER
    BY  DATEDIFF(O.DATETIME, I.DATETIME) DESC
 LIMIT  2
  ;

 

DATETIME에서 DATE로 형 변환
#DATE_FORMAT

 

첫 날만 해도 이걸 어케 외우지..? 했는데 그새 뚝딱! 반복 연습이 답이다.

SELECT  ANIMAL_ID, NAME, DATE_FORMAT(DATETIME,'%Y-%m-%d') 날짜
  FROM  ANIMAL_INS
 ORDER
    BY  ANIMAL_ID
  ;

 

카테고리 별 상품 개수 구하기
#COUNT #LEFT #GROUPBY
SELECT  CATEGORY, COUNT(1) PRODUCTS
  FROM  (SELECT *, LEFT(PRODUCT_CODE,2) CATEGORY
         FROM PRODUCT) P
 GROUP
    BY  CATEGORY
 ORDER
    BY  CATEGORY
  ;

 


 

와아. 이번 분류는 양이 꽤 많았다. 내일 일이 있어 내일 진도 분량까지 다 해버렸더니... 거의 3시간이 걸렸다!

놀라운 사실은 그동안 엉덩이 한 번 안 떼고 몰입했다는 것... 이거 왜 재밌지...?(어리둥절)