Tables
erDiagram
employees {
employee_id int PK
name varchar
}
performance_reviews {
review_id int PK
employee_id int FK
review_date date
rating int "1 ~ 5"
}
employees || -- o{ performance_reviews : review
Mermaid
복사
Question
Write a solution to find employees who have consistently improved their performance over their last three reviews.
•
An employee must have at least 3 review to be considered
•
The employee's last 3 reviews must show strictly increasing ratings (each review better than the previous)
•
Use the most recent 3 reviews based on review_date for each employee
•
Calculate the improvement score as the difference between the latest rating and the earliest rating among the last 3 reviews
Return the result table ordered by improvement score in descending order, then by name in ascending order.
The result format is in the following example.
DataFlow
•
at least 3 review -> where latest 3 reviews -> group by employee_id -> count review_id
•
reting increasing
•
diff first, last
Answer
WITH review_rn AS (
SELECT
*,
COUNT(review_id) OVER(PARTITION BY employee_id) AS cnt,
ROW_NUMBER() OVER(PARTITION BY employee_id ORDER BY review_date DESC) AS rn
FROM performance_reviews
),
review_filter AS (
SELECT
*
FROM review_rn
WHERE cnt >= 3
AND rn <= 3
),
review_pivot AS (
SELECT
employee_id,
MAX(CASE WHEN rn = 3 THEN rating END) AS one,
MAX(CASE WHEN rn = 2 THEN rating END) AS two,
MAX(CASE WHEN rn = 1 THEN rating END) AS three
FROM review_filter
GROUP BY employee_id
),
review_diff AS (
SELECT
*,
(three - one) AS diff
FROM review_pivot
WHERE one < two
AND two < three
)
SELECT
d.employee_id,
e.name,
d.diff AS improvement_score
FROM review_diff d
INNER JOIN employees e
ON d.employee_id = e.employee_id
ORDER BY d.diff DESC, e.name ASC;
SQL
복사
가독성을 위해서 모두 CTE로 작성
•
subquery 작성
•
비용이 작은 쿼리로 수정이 가능한 부분?
SELECT
d.employee_id,
e.name,
d.diff AS improvement_score
FROM (
SELECT
*,
(three - one) AS diff
FROM (
SELECT
employee_id,
MAX(CASE WHEN rn = 3 THEN rating END) AS one,
MAX(CASE WHEN rn = 2 THEN rating END) AS two,
MAX(CASE WHEN rn = 1 THEN rating END) AS three
FROM (
SELECT
*
FROM (
SELECT
*,
COUNT(review_id) OVER(PARTITION BY employee_id) AS cnt,
ROW_NUMBER() OVER(PARTITION BY employee_id ORDER BY review_date DESC) AS rn
FROM performance_reviews
) review_rn
WHERE cnt >= 3
AND rn <= 3
) review_filter
GROUP BY employee_id
) review_pivot
WHERE one < two
AND two < three
) d
INNER JOIN employees e
ON d.employee_id = e.employee_id
ORDER BY d.diff DESC, e.name ASC;
SQL
복사
subquery 치환 속도 변환 없음
WITH ranking AS (
SELECT
pr.employee_id,
e.name,
pr.rating,
RANK() OVER (PARTITION BY pr.employee_id ORDER BY pr.review_date DESC) AS ranks
FROM performance_reviews pr
JOIN employees e
ON pr.employee_id = e.employee_id
),
pivoted AS (
SELECT
employee_id,
name,
MAX(CASE WHEN ranks = 1 THEN rating END) AS latest_rating,
MAX(CASE WHEN ranks = 2 THEN rating END) AS sec_rating,
MAX(CASE WHEN ranks = 3 THEN rating END) AS third_latest_rating
FROM ranking
GROUP BY employee_id, name
)
SELECT
employee_id,
name,
latest_rating - third_latest_rating AS improvement_score
FROM pivoted
WHERE latest_rating IS NOT NULL
AND third_latest_rating IS NOT NULL
AND latest_rating > third_latest_rating
AND sec_rating > third_latest_rating
ORDER BY improvement_score DESC, name;
SQL
복사
in not null 사용 -> count 함수를 대체