코드카타 114번~116번

JIYUU·2025년 9월 30일

114번

문제

모든 연속된 두 학생씩 seat id를 서로 바꾼다. 학생 수가 홀수이면 마지막 학생의 id는 바꾸지 않는다.

결과 테이블은 id 오름차순으로 정렬해서 반환한다.

결과 형식은 아래 예시와 같다.

Input

idstudent
1Abbot
2Doris
3Emerson
4Green
5Jeames

Output

idstudent
1Doris
2Abbot
3Green
4Emerson
5Jeames

코드를 이것저것 만져보다가 LAG과 LEAD를 사용하면 해결할 수 있을 것 같았다.
거기에 IF를 추가하고 (잘 사용하지 않지만 이번에 사용해봤다.) COALESCE로 null이 되는 것을 방지했다.

SELECT id, IF(id%2 = 1, COALESCE(lead(student) over(), student), lag(student) over()) as student
FROM Seat

115번

문제

가장 많은 영화에 평점을 남긴 사용자의 이름을 찾아라. 만약 동점이 있으면, 사전순으로 더 앞선 이름을 반환한다.

2020년 2월에 평균 평점이 가장 높은 영화 이름을 찾아라. 만약 동점이 있으면, 사전순으로 더 앞선 영화 이름을 반환한다.

결과 형식은 아래 예시와 같다.

Input

Movies

movie_idtitle
1Avengers
2Frozen 2
3Joker

Users

user_idname
1Daniel
2Monica
3Maria
4James

MovieRating

movie_iduser_idratingcreated_at
1132020-01-12
1242020-02-11
1322020-02-12
1412020-01-01
2152020-02-17
2222020-02-01
2322020-03-01
3132020-02-22
3242020-02-25

Output

results
Daniel
Frozen 2

문제 핵심은 UNION ALL을 사용한다는 것인데, 두 가지 쿼리를 하나로 반환하는 것이 필요했다.

WITH a AS(
    SELECT u.name, count(m.user_id) as cnt
    FROM MovieRating m
    JOIN Users u
    ON m.user_id = u.user_id
    GROUP BY m.user_id
    ORDER BY cnt DESC, u.name ASC LIMIT 1
)
SELECT name AS results
FROM a
UNION ALL
SELECT title
FROM
(
    SELECT mv.title, AVG(mr.rating) as avg_rate
    FROM MovieRating mr
    JOIN Movies mv
    ON mr.movie_id = mv.movie_id
    WHERE created_at BETWEEN '2020-02-01' AND '2020-02-29'
    GROUP BY mr.movie_id
    ORDER BY avg_rate DESC, mv.title ASC LIMIT 1
) AS b

답이 조금 지저분한데, 이건 ORDER BY절에 AVG(), COUNT()를 사용하는 방법을 알았으면 더 깔끔하게 풀 수 있었다.
ORDER BY절에도 GROUP BY가 있으면 집계함수 사용이 가능하다는 점을 새로 배웠다.

116번

문제

당신은 식당 주인이고, 매장 확장을 고려하기 위해 데이터를 분석하려고 한다 (매일 최소 한 명의 손님은 있다고 가정한다).

손님이 지불한 금액에 대해 7일간 이동 평균을 계산하라. (즉, 해당 일자 + 이전 6일)
average_amount는 소수점 둘째 자리까지 반올림해야 한다.

결과 테이블은 visited_on을 기준으로 오름차순 정렬하여 반환한다.

결과 형식은 아래 예시와 같다.

Input

Customer

customer_idnamevisited_onamount
1Jhon2019-01-01100
2Daniel2019-01-02110
3Jade2019-01-03120
4Khaled2019-01-04130
5Winston2019-01-05110
6Elvis2019-01-06140
7Anna2019-01-07150
8Maria2019-01-0880
9Jaze2019-01-09110
1Jhon2019-01-10130
3Jade2019-01-10150

Output

visited_onamountaverage_amount
2019-01-07860122.86
2019-01-08840120
2019-01-09840120
2019-01-101000142.86

너무 어려워서 구글링을 통해 겨우 꾸역꾸역 답안을 작성...

WITH day AS (
    SELECT visited_on, SUM(amount) AS total
    FROM Customer
    GROUP BY visited_on
)
, window AS (
    SELECT
        visited_on,
        SUM(total) OVER (
            ORDER BY visited_on
            RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW
        ) AS amount,
        COUNT(*) OVER (
            ORDER BY visited_on
            RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW
        ) AS day_window
    FROM day
)
SELECT
    visited_on,
    amount,
    ROUND(amount / 7, 2) AS average_amount
FROM window
WHERE day_window = 7
ORDER BY visited_on

0개의 댓글