SQL 문제풀이 복습
문제 링크
기본적인 window함수 문제.
rank()는 공동 등수가 발생할 경우 다음 등수를 건너뛴다.
(1등이 2명일 경우 다음 값은 3이 됨)
dense_rank()는 공동 등수가 발생하더라도 다음 등수를 건너뛰지 않는다.
(1등이 2명이더라도 다음 값이 2가 됨)
SELECT score,
Dense_rank()
OVER(
ORDER BY score DESC) AS "rank"
FROM Scores
ORDER BY 1 DESC;
문제 링크
union + join + count
SELECT a.player_id,
p.player_name,
Count(*) AS "grand_slams_count"
FROM (SELECT Wimbledon AS "player_id"
FROM Championships
UNION ALL
SELECT Fr_open
FROM Championships
UNION ALL
SELECT US_open
FROM Championships
UNION ALL
SELECT Au_open
FROM Championships) a
JOIN Players p
ON a.player_id = p.player_id
GROUP BY 1;
문제 링크
1트(5/8)와 2트(6/21) 때의 풀이가 같았어서
오늘은 일부러 다르게 풀어서 해결했다.
즉, primary_flag = Y인 employee를 구하는 쿼리와
primary_flag = N이면서 숫자가 하나밖에 없는 쿼리를 각각 짜서
union하는 방식이 아니라,
window 함수를 써서 row_id를 만들되
order by의 조건을 employee_id와 primary_flag 기준으로 오름차순하도록 하는 것.
이렇게 한 다음 결과를 인라인뷰로 저장하고 row_id가 1인 것만 불러오면 된다.
이 방식대로 하면 primary_flag가 뭐든간에
있는 놈은 있는대로 불러오고 없는 놈은 자동으로 현재 소속부서가 불러와지게 됨.
SELECT employee_id,
department_id
FROM (SELECT employee_id,
department_id,
primary_flag,
Rank()
OVER(
partition BY employee_id
ORDER BY employee_id, primary_flag) AS "row_id"
FROM Employee) a
WHERE row_id = '1';
문제 링크
찾아보니 본격적인 부트캠프가 시작하기도 전인
4월 초에 처음 풀었었던 문제였다.
그 때는 이게 왜 그렇게 어려웠던 걸까ㅠ 허허..
SELECT DISTINCT h.CAR_ID,
CASE
WHEN rented IS NULL THEN '대여 가능'
WHEN rented IS NOT NULL THEN '대여중'
end AS "AVAILABILITY"
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY h
LEFT JOIN (SELECT car_id AS "rented"
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE '2022-10-16' BETWEEN START_DATE AND END_DATE) a
ON h.CAR_ID = a.rented
ORDER BY 1 DESC;
문제 링크
으으 치사해
어렵지도 않은데 괜히 조건만 복잡하게 꼬아서 내는 이런 문제 진짜 별로;
SELECT c.CAR_ID,
c.CAR_TYPE,
Round(daily_fee * 30 * ( 1 - ( DISCOUNT_RATE / 100 ) )) AS "FEE"
FROM CAR_RENTAL_COMPANY_CAR c
JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY h
ON c.CAR_ID = h.CAR_ID
AND c.CAR_TYPE IN ( '세단', 'SUV' )
JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN d
ON c.CAR_TYPE = d.CAR_TYPE
AND d.DURATION_TYPE = '30일 이상'
WHERE c.CAR_ID NOT IN (SELECT CAR_ID
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE ( '2022-11-01 00:00:00' BETWEEN
START_DATE AND END_DATE
)
OR ( '2022-11-30 23:59:59' BETWEEN
START_DATE AND END_DATE ))
GROUP BY 1
HAVING FEE >= 500000
AND FEE < 2000000
ORDER BY 3 DESC,
2 ASC,
1 DESC;
문제 링크
이것도 join의 조건이 괜히 복잡하게 생겨서 그렇지
그것만 놓치지 않고 잘 주면 별 건 없다.
join의 조건을 줄 때도 case when을 쓸 수 있다, 정도만 기억하면 될 듯.
굳이 하나를 더 꼽자면 연산을 할 때도 case when을 쓰는 방법 정도?
SELECT HISTORY_ID,
Round(DAILY_FEE * ( Datediff(END_DATE, START_DATE) + 1 ) *
( 1 - ( CASE
WHEN
discount_rate IS NULL THEN 0
ELSE
discount_rate / 100
end )
)
) AS
"FEE"
FROM CAR_RENTAL_COMPANY_CAR c
JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY h
ON c.CAR_ID = h.CAR_ID
AND c.CAR_TYPE = '트럭'
LEFT JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN d
ON c.CAR_TYPE = d.CAR_TYPE
AND CASE
WHEN Datediff(END_DATE, START_DATE) + 1 >= 90 THEN
'90일 이상'
WHEN Datediff(END_DATE, START_DATE) + 1 >= 30 THEN
'30일 이상'
WHEN Datediff(END_DATE, START_DATE) + 1 >= 7 THEN
'7일 이상'
end = d.DURATION_TYPE
ORDER BY 2 DESC,
1 DESC;
문제 링크
where절 안에 서브쿼리를 넣어서
기준 시점 동안 5회 이상 렌트된 이력이 있는 car_id만 뽑는 것이 키.
그거 외엔 딱히 어려울 거 없음.
SELECT Month(START_DATE) AS "MONTH",
h.CAR_ID,
Count(*) AS "RECORDS"
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY h
WHERE START_DATE BETWEEN '2022-08-01' AND '2022-10-31'
AND CAR_ID IN (SELECT car_id
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE START_DATE BETWEEN '2022-08-01' AND '2022-10-31'
GROUP BY 1
HAVING Count(*) >= 5)
GROUP BY 1,
2
ORDER BY 1,
2 DESC;
문제 링크
case when, date_format, where.. 기냥기냥 무난한 문제
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",
CASE
WHEN Datediff(END_DATE, START_DATE) + 1 >= 30 THEN '장기 대여'
ELSE '단기 대여'
end AS "RENT_TYPE"
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE START_DATE BETWEEN '2022-09-01' AND '2022-09-30'
ORDER BY 1 DESC;