NOW(): 현재의 날짜와 시간을 반환합니다.CURDATE(): 현재의 날짜만 반환합니다.CURTIME(): 현재의 시간만 반환합니다.YEAR(date): 주어진 날짜의 연도를 반환합니다.MONTH(date): 주어진 날짜의 월을 반환합니다.DAY(date): 주어진 날짜의 일을 반환합니다.HOUR(time): 주어진 시간의 시간을 반환합니다.MINUTE(time): 주어진 시간의 분을 반환합니다.SECOND(time): 주어진 시간의 초를 반환합니다.DATEDIFF(date1, date2): 두 날짜 사이의 차이를 일 단위로 반환합니다.TIMEDIFF(time1, time2): 두 시간 사이의 차이를 반환합니다.DATE_FORMAT(date, format): 주어진 날짜를 지정된 포맷으로 변환하여 반환합니다. 예를 들어, DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s')는 현재 날짜와 시간을 'YYYY-MM-DD HH:MM:SS' 형식으로 반환합니다.DATE_ADD(date, INTERVAL expr type): 주어진 날짜에서 특정 기간을 더한 날짜를 반환합니다. 예: DATE_ADD('2023-01-01', INTERVAL 1 DAY).DATE_SUB(date, INTERVAL expr type): 주어진 날짜에서 특정 기간을 뺀 날짜를 반환합니다.UNIX_TIMESTAMP(): 현재 날짜와 시간을 UNIX 타임스탬프로 반환합니다.FROM_UNIXTIME(unix_timestamp): UNIX 타임스탬프를 날짜와 시간으로 변환합니다.이 함수들을 사용함으로써, MySQL에서 날짜와 시간 데이터를 효율적으로 관리하고 조작할 수 있습니다. 사용 예시나 추가적인 함수에 대한 정보는 MySQL 공식 문서에서 찾아볼 수 있습니다.
다음은 어느 자동차 대여 회사에서 대여 중인 자동차들의 정보를 담은 CAR_RENTAL_COMPANY_CAR 테이블과 자동차 대여 기록 정보를 담은 CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블과 자동차 종류 별 대여 기간 종류 별 할인 정책 정보를 담은 CAR_RENTAL_COMPANY_DISCOUNT_PLAN 테이블 입니다.
CAR_RENTAL_COMPANY_CAR 테이블은 아래와 같은 구조로 되어있으며, CAR_ID, CAR_TYPE, DAILY_FEE, OPTIONS 는 각각 자동차 ID, 자동차 종류, 일일 대여 요금(원), 자동차 옵션 리스트를 나타냅니다.
| Column name | Type | Nullable |
|---|---|---|
| CAR_ID | INTEGER | FALSE |
| CAR_TYPE | VARCHAR(255) | FALSE |
| DAILY_FEE | INTEGER | FALSE |
| OPTIONS | VARCHAR(255) | FALSE |
자동차 종류는 '세단', 'SUV', '승합차', '트럭', '리무진' 이 있습니다. 자동차 옵션 리스트는 콤마(',')로 구분된 키워드 리스트(예: ''열선시트,스마트키,주차감지센서'')로 되어있으며, 키워드 종류는 '주차감지센서', '스마트키', '네비게이션', '통풍시트', '열선시트', '후방카메라', '가죽시트' 가 있습니다.
CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블은 아래와 같은 구조로 되어있으며, HISTORY_ID, CAR_ID, START_DATE, END_DATE 는 각각 자동차 대여 기록 ID, 자동차 ID, 대여 시작일, 대여 종료일을 나타냅니다.
| Column name | Type | Nullable |
|---|---|---|
| HISTORY_ID | INTEGER | FALSE |
| CAR_ID | INTEGER | FALSE |
| START_DATE | DATE | FALSE |
| END_DATE | DATE | FALSE |
CAR_RENTAL_COMPANY_DISCOUNT_PLAN 테이블은 아래와 같은 구조로 되어있으며, PLAN_ID, CAR_TYPE, DURATION_TYPE, DISCOUNT_RATE 는 각각 요금 할인 정책 ID, 자동차 종류, 대여 기간 종류, 할인율(%)을 나타냅니다.
| Column name | Type | Nullable |
|---|---|---|
| PLAN_ID | INTEGER | FALSE |
| CAR_TYPE | VARCHAR(255) | FALSE |
| DURATION_TYPE | VARCHAR(255) | FALSE |
| DISCOUNT_RATE | INTEGER | FALSE |
할인율이 적용되는 대여 기간 종류로는 '7일 이상' (대여 기간이 7일 이상 30일 미만인 경우), '30일 이상' (대여 기간이 30일 이상 90일 미만인 경우), '90일 이상' (대여 기간이 90일 이상인 경우) 이 있습니다. 대여 기간이 7일 미만인 경우 할인정책이 없습니다.
CAR_RENTAL_COMPANY_CAR 테이블과 CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블과 CAR_RENTAL_COMPANY_DISCOUNT_PLAN 테이블에서 자동차 종류가 '트럭'인 자동차의 대여 기록에 대해서 대여 기록 별로 대여 금액(컬럼명: FEE)을 구하여 대여 기록 ID와 대여 금액 리스트를 출력하는 SQL문을 작성해주세요. 결과는 대여 금액을 기준으로 내림차순 정렬하고, 대여 금액이 같은 경우 대여 기록 ID를 기준으로 내림차순 정렬해주세요.
예를 들어 CAR_RENTAL_COMPANY_CAR 테이블과 CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블과 CAR_RENTAL_COMPANY_DISCOUNT_PLAN 테이블이 다음과 같다면
| CAR_ID | CAR_TYPE | DAILY_FEE | OPTIONS |
|---|---|---|---|
| 1 | 트럭 | 26000 | 가죽시트,열선시트,후방카메라 |
| 2 | SUV | 14000 | 스마트키,네비게이션,열선시트 |
| 3 | 트럭 | 32000 | 주차감지센서,후방카메라,가죽시트 |
| HISTORY_ID | CAR_ID | START_DATE | END_DATE |
|---|---|---|---|
| 1 | 1 | 2022-07-27 | 2022-08-02 |
| 2 | 1 | 2022-08-03 | 2022-08-04 |
| 3 | 2 | 2022-08-05 | 2022-08-05 |
| 4 | 2 | 2022-08-09 | 2022-08-12 |
| 5 | 3 | 2022-09-16 | 2022-10-15 |
| PLAN_ID | CAR_TYPE | DURATION_TYPE | DISCOUNT_RATE |
|---|---|---|---|
| 1 | 트럭 | 7일 이상 | 5% |
| 2 | 트럭 | 30일 이상 | 7% |
| 3 | 트럭 | 90일 이상 | 10% |
| 4 | 세단 | 7일 이상 | 5% |
| 5 | 세단 | 30일 이상 | 10% |
| 6 | 세단 | 90일 이상 | 15% |
자동차 종류가 '트럭' 인 자동차의 대여 기록에 대해서 대여 기간을 구하면,
대여 기간 별로 일일 대여 요금에 알맞은 할인율을 곱하여 금액을 구하면 다음과 같습니다.
| HISTORY_ID | FEE |
|---|---|
| 5 | 892800 |
| 1 | 172900 |
| 2 | 52000 |
FEE의 경우 예시처럼 정수부분만 출력되어야 합니다.
SELECT HISTORY_ID, ROUND(DAILY_FEE * 0.01 * (100-CASE WHEN
DISCOUNT_RATE IS NULL THEN 0
ELSE DISCOUNT_RATE END) * (DATEDIFF(END_DATE,START_DATE) + 1)) AS FEE
FROM CAR_RENTAL_COMPANY_CAR AS A
INNER JOIN
CAR_RENTAL_COMPANY_RENTAL_HISTORY AS B
ON A.CAR_ID = B.CAR_ID
LEFT JOIN
CAR_RENTAL_COMPANY_DISCOUNT_PLAN AS C
ON C.CAR_TYPE = A.CAR_TYPE AND
CASE WHEN DATEDIFF(B.END_DATE,B.START_DATE) + 1 >= 90
THEN '90일 이상'
WHEN DATEDIFF(B.END_DATE,B.START_DATE) + 1 >= 30
THEN '30일 이상'
WHEN DATEDIFF(B.END_DATE,B.START_DATE) + 1 >=7
THEN '7일 이상'END = C.DURATION_TYPE
WHERE A.CAR_TYPE = '트럭'
ORDER BY FEE DESC, B.HISTORY_ID DESC
다음은 아이스크림 가게의 상반기 주문 정보를 담은 FIRST_HALF 테이블과 7월의 아이스크림 주문 정보를 담은 JULY 테이블입니다. FIRST_HALF 테이블 구조는 다음과 같으며, SHIPMENT_ID, FLAVOR, TOTAL_ORDER는 각각 아이스크림 공장에서 아이스크림 가게까지의 출하 번호, 아이스크림 맛, 상반기 아이스크림 총주문량을 나타냅니다. FIRST_HALF 테이블의 기본 키는 FLAVOR입니다. FIRST_HALF테이블의 SHIPMENT_ID는 JULY테이블의 SHIPMENT_ID의 외래 키입니다.
| NAME | TYPE | NULLABLE |
|---|---|---|
| SHIPMENT_ID | INT(N) | FALSE |
| FLAVOR | VARCHAR(N) | FALSE |
| TOTAL_ORDER | INT(N) | FALSE |
JULY 테이블 구조는 다음과 같으며, SHIPMENT_ID, FLAVOR, TOTAL_ORDER 은 각각 아이스크림 공장에서 아이스크림 가게까지의 출하 번호, 아이스크림 맛, 7월 아이스크림 총주문량을 나타냅니다. JULY 테이블의 기본 키는 SHIPMENT_ID입니다. JULY테이블의 FLAVOR는 FIRST_HALF 테이블의 FLAVOR의 외래 키입니다. 7월에는 아이스크림 주문량이 많아 같은 아이스크림에 대하여 서로 다른 두 공장에서 아이스크림 가게로 출하를 진행하는 경우가 있습니다. 이 경우 같은 맛의 아이스크림이라도 다른 출하 번호를 갖게 됩니다.
| NAME | TYPE | NULLABLE |
|---|---|---|
| SHIPMENT_ID | INT(N) | FALSE |
| FLAVOR | VARCHAR(N) | FALSE |
| TOTAL_ORDER | INT(N) | FALSE |
7월 아이스크림 총 주문량과 상반기의 아이스크림 총 주문량을 더한 값이 큰 순서대로 상위 3개의 맛을 조회하는 SQL 문을 작성해주세요.
예를 들어 FIRST_HALF 테이블이 다음과 같고
| SHIPMENT_ID | FLAVOR | TOTAL_ORDER |
|---|---|---|
| 101 | chocolate | 3200 |
| 102 | vanilla | 2800 |
| 103 | mint_chocolate | 1700 |
| 104 | caramel | 2600 |
| 105 | white_chocolate | 3100 |
| 106 | peach | 2450 |
| 107 | watermelon | 2150 |
| 108 | mango | 2900 |
| 109 | strawberry | 3100 |
| 110 | melon | 3150 |
| 111 | orange | 2900 |
| 112 | pineapple | 2900 |
JULY테이블이 다음과 같다면
| SHIPMENT_ID | FLAVOR | TOTAL_ORDER |
|---|---|---|
| 101 | chocolate | 520 |
| 102 | vanilla | 560 |
| 103 | mint_chocolate | 400 |
| 104 | caramel | 460 |
| 105 | white_chocolate | 350 |
| 106 | peach | 500 |
| 107 | watermelon | 780 |
| 108 | mango | 790 |
| 109 | strawberry | 520 |
| 110 | melon | 400 |
| 111 | orange | 250 |
| 112 | pineapple | 200 |
| 208 | mango | 110 |
| 209 | strawberry | 220 |
7월 아이스크림 총주문량과 상반기의 아이스크림 총 주문량을 더한 값이 큰 순서대로 상위 3개의 맛을 조회하면 strawberry(520 + 220 + 3,100 = 3,840), mango(790 + 110 + 2,900 = 3,800), chocolate(520 + 3,200 = 3,720) 순입니다. 따라서 SQL 문을 실행하면 다음과 같이 나와야 합니다.
FLAVOR
strawberry
mango
chocolate
WITH U AS (SELECT * FROM FIRST_HALF
UNION ALL
SELECT * FROM JULY)
SELECT A.FLAVOR
FROM
(SELECT FLAVOR, SUM(TOTAL_ORDER) AS TOT FROM U
GROUP BY FLAVOR ORDER BY TOT DESC LIMIT 3) AS A
ANIMAL_OUTS 테이블은 동물 보호소에서 입양 보낸 동물의 정보를 담은 테이블입니다. ANIMAL_OUTS 테이블 구조는 다음과 같으며, ANIMAL_ID, ANIMAL_TYPE, DATETIME, NAME, SEX_UPON_OUTCOME는 각각 동물의 아이디, 생물 종, 입양일, 이름, 성별 및 중성화 여부를 나타냅니다.
| NAME | TYPE | NULLABLE |
|---|---|---|
| ANIMAL_ID | VARCHAR(N) | FALSE |
| ANIMAL_TYPE | VARCHAR(N) | FALSE |
| DATETIME | DATETIME | FALSE |
| NAME | VARCHAR(N) | TRUE |
| SEX_UPON_OUTCOME | VARCHAR(N) | FALSE |
보호소에서는 몇 시에 입양이 가장 활발하게 일어나는지 알아보려 합니다. 0시부터 23시까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성해주세요. 이때 결과는 시간대 순으로 정렬해야 합니다.
SQL문을 실행하면 다음과 같이 나와야 합니다.
| HOUR | COUNT |
|---|---|
| 0 | 0 |
| 1 | 0 |
| 2 | 0 |
| 3 | 0 |
| 4 | 0 |
| 5 | 0 |
| 6 | 0 |
| 7 | 3 |
| 8 | 1 |
| 9 | 1 |
| 10 | 2 |
| 11 | 13 |
| 12 | 10 |
| 13 | 14 |
| 14 | 9 |
| 15 | 7 |
| 16 | 10 |
| 17 | 12 |
| 18 | 16 |
| 19 | 2 |
| 20 | 0 |
| 21 | 0 |
| 22 | 0 |
| 23 | 0 |
본 문제는 Kaggle의 "Austin Animal Center Shelter Intakes and Outcomes"에서 제공하는 데이터를 사용하였으며 ODbL의 적용을 받습니다.
WITH RECURSIVE TIMERANGE AS
(SELECT 0 AS HOUR
UNION ALL
SELECT HOUR + 1 FROM TIMERANGE
WHERE HOUR + 1 < 24)
SELECT A.HOUR, CASE WHEN B.COUNT IS NULL THEN 0 ELSE B.COUNT END AS COUNT
FROM TIMERANGE AS A
LEFT JOIN
(SELECT HOUR(DATETIME) AS HOUR, COUNT(ANIMAL_ID) AS COUNT
FROM ANIMAL_OUTS
GROUP BY HOUR) AS B
ON A.HOUR = B.HOUR
GROUP BY A.HOUR
ORDER BY A.HOUR ASC
다음은 어느 의류 쇼핑몰의 온라인 상품 판매 정보를 담은 ONLINE_SALE 테이블과 오프라인 상품 판매 정보를 담은 OFFLINE_SALE 테이블 입니다. ONLINE_SALE 테이블은 아래와 같은 구조로 되어있으며 ONLINE_SALE_ID, USER_ID, PRODUCT_ID, SALES_AMOUNT, SALES_DATE는 각각 온라인 상품 판매 ID, 회원 ID, 상품 ID, 판매량, 판매일을 나타냅니다.
| Column name | Type | Nullable |
|---|---|---|
| ONLINE_SALE_ID | INTEGER | FALSE |
| USER_ID | INTEGER | FALSE |
| PRODUCT_ID | INTEGER | FALSE |
| SALES_AMOUNT | INTEGER | FALSE |
| SALES_DATE | DATE | FALSE |
동일한 날짜, 회원 ID, 상품 ID 조합에 대해서는 하나의 판매 데이터만 존재합니다.
OFFLINE_SALE 테이블은 아래와 같은 구조로 되어있으며 OFFLINE_SALE_ID, PRODUCT_ID, SALES_AMOUNT, SALES_DATE는 각각 오프라인 상품 판매 ID, 상품 ID, 판매량, 판매일을 나타냅니다.
| Column name | Type | Nullable |
|---|---|---|
| OFFLINE_SALE_ID | INTEGER | FALSE |
| PRODUCT_ID | INTEGER | FALSE |
| SALES_AMOUNT | INTEGER | FALSE |
| SALES_DATE | DATE | FALSE |
동일한 날짜, 상품 ID 조합에 대해서는 하나의 판매 데이터만 존재합니다.
ONLINE_SALE 테이블과 OFFLINE_SALE 테이블에서 2022년 3월의 오프라인/온라인 상품 판매 데이터의 판매 날짜, 상품ID, 유저ID, 판매량을 출력하는 SQL문을 작성해주세요. OFFLINE_SALE 테이블의 판매 데이터의 USER_ID 값은 NULL 로 표시해주세요. 결과는 판매일을 기준으로 오름차순 정렬해주시고 판매일이 같다면 상품 ID를 기준으로 오름차순, 상품ID까지 같다면 유저 ID를 기준으로 오름차순 정렬해주세요.
예를 들어 ONLINE_SALE 테이블이 다음과 같고
| ONLINE_SALE_ID | USER_ID | PRODUCT_ID | SALES_AMOUNT | SALES_DATE |
|---|---|---|---|---|
| 1 | 1 | 3 | 2 | 2022-02-25 |
| 2 | 4 | 4 | 1 | 2022-03-01 |
| 4 | 2 | 2 | 2 | 2022-03-02 |
| 3 | 6 | 3 | 3 | 2022-03-02 |
| 5 | 5 | 5 | 1 | 2022-03-03 |
| 6 | 5 | 7 | 1 | 2022-04-06 |
OFFLINE_SALE 테이블이 다음과 같다면
| OFFLINE_SALE_ID | PRODUCT_ID | SALES_AMOUNT | SALES_DATE |
|---|---|---|---|
| 1 | 1 | 2 | 2022-02-21 |
| 4 | 1 | 2 | 2022-03-01 |
| 3 | 3 | 3 | 2022-03-01 |
| 2 | 4 | 1 | 2022-03-01 |
| 5 | 2 | 1 | 2022-03-03 |
| 6 | 2 | 1 | 2022-04-01 |
각 테이블의 2022년 3월의 판매 데이터를 합쳐서, 정렬한 결과는 다음과 같아야 합니다.
| SALES_DATE | PRODUCT_ID | USER_ID | SALES_AMOUNT |
|---|---|---|---|
| 2022-03-01 | 1 | NULL | 2 |
| 2022-03-01 | 3 | NULL | 3 |
| 2022-03-01 | 4 | NULL | 1 |
| 2022-03-01 | 4 | 4 | 1 |
| 2022-03-02 | 2 | 2 | 2 |
| 2022-03-02 | 3 | 6 | 3 |
| 2022-03-03 | 2 | NULL | 1 |
| 2022-03-03 | 5 | 5 | 1 |
(SELECT DATE_FORMAT(SALES_DATE,"%Y-%m-%d") AS SALES_DATE, PRODUCT_ID,
USER_ID, SALES_AMOUNT FROM ONLINE_SALE
WHERE SALES_DATE LIKE '%2022-03%')
UNION ALL
(SELECT DATE_FORMAT(SALES_DATE, '%Y-%m-%d') AS SALES_DATE, PRODUCT_ID, NULL AS USER_ID,
SALES_AMOUNT FROM OFFLINE_SALE
WHERE SALES_DATE LIKE '%2022-03%')
ORDER BY 1,2,3