4편 - String, Date
[출제 빈도 : 낮음, 평균 점수 : 낮음, 문제세트 : 16]
[조건]
1. PRODUCT_CODE의 앞 2자리 자르고 GROUP BY
2. GROUP 별 개수 구하기
3. 카테고리 코드 기준 오름차순 정렬
[답안]
SELECT LEFT(PRODUCT_CODE, 2) AS CATEGORY, COUNT(*) AS PRODUCTS
FROM PRODUCT
GROUP BY LEFT(PRODUCT_CODE, 2)
ORDER BY CATEGORY
SELECT SUBSTR(PRODUCT_CODE, 1, 2) AS CATEGORY, COUNT(PRODUCT_ID) AS PRODUCTS
FROM PRODUCT
GROUP BY SUBSTR(PRODUCT_CODE, 1, 2)
ORDER BY CATEGORY
LEFT(컬럼명, 왼쪽부터 가져올 문자 개수)
SUBSTR(컬럼명, 시작인덱스, 끝인덱스)
SELECT I.ANIMAL_ID, I.NAME
FROM ANIMAL_INS AS I
JOIN ANIMAL_OUTS AS O
ON I.ANIMAL_ID = O.ANIMAL_ID
ORDER BY O.DATETIME - I.DATETIME DESC
LIMIT 2
입양간 날짜에서 보호시작된 날을 뺀 값을 내림차순 정렬한 뒤, limit 2를 통해 최상위 2개만 보여준다.
DATEDIFF(구분자, 날짜1, 날짜2)
날짜1-날짜2
2018-10-13 - 2018-10-15 하면 2가 나옴. 처음날짜부터 끝까지 세려면 +1 해야함. (아래의 자동차 문제에서 필요..)
그냥 두 날짜를 빼도 되지만, DATEDIFF 함수를 이용해도 된다. (다른 사람 풀이에 있길래.. 가져와봤슴ㄴㄷ.)
-- 1. CASE WHEN 이용
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
-- 조건 간략히
SELECT ANIMAL_ID,
NAME,
CASE
WHEN SEX_UPON_INTAKE LIKE 'Neutered%'
OR SEX_UPON_INTAKE LIKE 'Spayed%' THEN 'O'
ELSE 'X'
END '중성화'
FROM ANIMAL_INS
ORDER BY ANIMAL_ID
--2. IF 이용
SELECT ANIMAL_ID, NAME,
IF(SEX_UPON_INTAKE LIKE 'Neutered%' OR SEX_UPON_INTAKE LIKE 'Spayed%', 'O', 'X') AS '중성화'
FROM ANIMAL_INS
ORDER BY ANIMAL_ID
SELECT
CASE
WHEN 조건1 THEN '조건1 반환값'
WHEN 조건2 THEN '조건2 반환값'
ELSE '충족조건 없을 때 반환값'
END 컬럼명 지정
FROM 테이블명
SELECT IF(required, '필수', '선택') AS '필수여부'
FROM 테이블명
SELECT ANIMAL_ID, NAME, SEX_UPON_INTAKE
FROM ANIMAL_INS
WHERE NAME IN ('Lucy', 'Ella', 'Pickle', 'Rogan', 'Sabrina', 'Mitty')
ORDER BY ANIMAL_ID
SELECT ORDER_ID, PRODUCT_ID, DATE_FORMAT(OUT_DATE, '%Y-%m-%d'),
CASE
WHEN OUT_DATE <= '2022-05-01' THEN '출고완료'
WHEN OUT_DATE > '2022-05-01' THEN '출고대기'
ELSE '출고미정'
END '출고여부'
FROM FOOD_ORDER
ORDER BY ORDER_ID
SELECT CAR_ID, ROUND(AVG(DATEDIFF(END_DATE, START_DATE)+1), 1) AS AVERAGE_DURATION
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
GROUP BY CAR_ID
HAVING AVERAGE_DURATION >= 7
ORDER BY AVERAGE_DURATION DESC, CAR_ID DESC
DATEDIFF(끝날짜, 시작날짜)를 하고 1을 더해주지 않으면 원하는 값을 산출할 수 없다.
뺀 후, +1을 해주어야 대여 기간을 구할 수 있다.
SELECT A.APNT_NO, P.PT_NAME, P.PT_NO, A.MCDP_CD, D.DR_NAME, A.APNT_YMD
FROM APPOINTMENT AS A
JOIN DOCTOR AS D
ON A.MDDR_ID = D.DR_ID
JOIN PATIENT AS P
ON A.PT_NO = P.PT_NO
WHERE A.APNT_YMD LIKE '2022-04-13%'
AND A.APNT_CNCL_YN = 'N'
AND A.MCDP_CD = 'CS'
ORDER BY A.APNT_YMD
SELECT HISTORY_ID,
CAR_ID,
DATE_FORMAT(START_DATE, '%Y-%m-%d') AS START_DATE,
DATE_FORMAT(END_DATE, '%Y-%m-%d') AS END_DATE,
IF(DATEDIFF(END_DATE, START_DATE) + 1 >= 30, '장기 대여', '단기 대여') AS RENT_TYPE
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE START_DATE LIKE '2022-09%'
ORDER BY HISTORY_ID DESC
"대여 시작일이 2022년 9월에 속하는"을 못봐서 5분은 까먹었다.. !
구현해야 하는 조건을 명확하게 파악한 뒤 두들기자.
SELECT USER_ID,
NICKNAME,
CONCAT(CITY, ' ', STREET_ADDRESS1, ' ', STREET_ADDRESS2) AS 전체주소,
CONCAT(SUBSTR(TLNO, 1, 3), '-', SUBSTR(TLNO, 4, 4), '-', SUBSTR(TLNO, 8, 4)) AS 전화번호
FROM USED_GOODS_BOARD AS B
LEFT JOIN USED_GOODS_USER AS U
ON B.WRITER_ID = U.USER_ID
GROUP BY B.WRITER_ID
HAVING COUNT(*) >= 3
ORDER BY U.USER_ID DESC
CONCAT(CITY, ' ', STREET_ADDRESS1, ' ', STREET_ADDRESS2) AS 전체주소,
공백을 두고 합치기
CONCAT(SUBSTR(TLNO, 1, 3), '-', SUBSTR(TLNO, 4, 4), '-', SUBSTR(TLNO, 8, 4))
전화번호 사이에 하이픈(-) 추가
SELECT CONCAT('/home/grep/src/', B.BOARD_ID, '/', FILE_ID, FILE_NAME, FILE_EXT) AS FILE_PATH
FROM USED_GOODS_FILE AS F
LEFT JOIN USED_GOODS_BOARD AS B
ON F.BOARD_ID = B.BOARD_ID
WHERE B.VIEWS = (SELECT MAX(VIEWS)
FROM USED_GOODS_BOARD)
ORDER BY FILE_ID DESC
"file_id로 내림차순 정렬"..
SELECT DISTINCT(H.CAR_ID)
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY AS H
LEFT JOIN CAR_RENTAL_COMPANY_CAR AS C
ON H.CAR_ID = C.CAR_ID
WHERE C.CAR_TYPE = '세단'
AND H.START_DATE LIKE '2022-10%'
ORDER BY H.CAR_ID DESC
SELECT H.CAR_ID
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY AS H
LEFT JOIN CAR_RENTAL_COMPANY_CAR AS C
ON H.CAR_ID = C.CAR_ID
WHERE C.CAR_TYPE = '세단'
AND H.START_DATE LIKE '2022-10%'
GROUP BY H.CAR_ID
ORDER BY H.CAR_ID DESC
자동차 ID 리스트는 중복이 없어야 하며 -> distinct 또는 group by로 구현.
테이블에 카테고리라는 컬럼이 존재할 때, 이 카테고리 값이 몇 종류가 있는지 알고 싶은 경우!
카테고리를 조회할 때 이 값이 중복되면 안 되기 때문에 DISTINCT를 사용한다.
-> COUNT(DISTINCT(컬럼명))을 통해 한 테이블 내에 카테고리가 몇 종류 있는지 알 수 있다.
SELECT BOARD_ID,
WRITER_ID,
TITLE,
PRICE,
CASE
WHEN STATUS = 'DONE' THEN '거래완료'
WHEN STATUS = 'SALE' THEN '판매중'
ELSE '예약중'
END STATUS
FROM USED_GOODS_BOARD
WHERE CREATED_DATE = '2022-10-05'
ORDER BY BOARD_ID DESC
🎨🎭🎪 복습이 필요한 문제 이렇게 긴 쿼리는 처음이라 ..
SELECT T.HISTORY_ID,
T.PERIOD * ROUND(T.DAILY_FEE * (IF(P.DISCOUNT_RATE IS NULL, 1, (1-P.DISCOUNT_RATE/100)))) AS FEE
FROM (SELECT C.CAR_ID, C.CAR_TYPE, C.DAILY_FEE, H.HISTORY_ID, H.START_DATE, H.END_DATE,
DATEDIFF(H.END_DATE, H.START_DATE)+1 AS PERIOD,
CASE
WHEN DATEDIFF(H.END_DATE, H.START_DATE)+1 >= 90 THEN '90일 이상'
WHEN DATEDIFF(H.END_DATE, H.START_DATE)+1 >= 30 THEN '30일 이상'
WHEN DATEDIFF(H.END_DATE, H.START_DATE)+1 >= 7 THEN '7일 이상'
ELSE '7일 미만'
END 'DURATION_TYPE'
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY AS H
JOIN CAR_RENTAL_COMPANY_CAR AS C
ON H.CAR_ID = C.CAR_ID
) AS T
LEFT JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN AS P
ON P.CAR_TYPE = T.CAR_TYPE
AND P.DURATION_TYPE = T.DURATION_TYPE
WHERE T.CAR_TYPE = '트럭'
ORDER BY FEE DESC, T.HISTORY_ID DESC
from절에서 car_type과 대여기간타입 컬럼을 포함한 새로운 테이블을 만든다. (CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블 + CAR_RENTAL_COMPANY_CAR + 대여기간타입)
새로운 테이블에 CAR_TYPE과 DURATION_TYPE(대여기간타입/ 7일미만, 7일이상, 30일이상, 90일이상)으로 CAR_RENTAL_COMPANY_DISCOUNT_PLAN 을 LEFT JOIN한다.
7일미만도 따로 타입으로 추가해야 한다. 우리가 찾는, 즉 7일이상, 30일이상, 90일이상의 경우 테이블에 있어 할인율을 적용하지만. 7일미만의 경우 할인율 적용없이 원가로 계산하기 때문이다.
7일미만의 경우 조인했을 때 NULL값으로 처리되므로, 마지막에 SELECT할 때 NULL처리를 해주어야 한다.
이때 무조건 alias 해줘야 한다!