[LEETCODE 문제풀이] (WINDOW FUNCTION) #178 & #176번

윤상혁·2025년 11월 7일

지난 프로그래머스 JOIN 문제에 이어서, LEETCODE SQL WINDOW FUNCTION 문제를 풀기 시작하였습니다.

오늘은, 나름 EASY(?) PART의 WINDOW FUNCTION 문제를 2개 풀었습니다.

이전 게시글들과 같이 정답 코드 공유하고 설명하고, 제가 설명하고 싶은 개념들을 설명할까 합니다.

(음..? EASY가 아니라 MEDIUM이었네요..ㅎㅎ.. CLAUDE가 EASY라고 해서 EASY인지 알았는데...)


#178번

1. 문제 소개

*테이블

SCORES(ID(PK),SCORE)
->SCORE은 소수점 둘째자리까지 표시된 실수

*문제

Write a solution to find the rank of the scores. The ranking should be calculated according to the following rules:

밑에 조건을 만족하는 SCORE RANK를 구하라.

※조건들

1.점수는 내림차순(DESC)
2.동점은 같은 등수
3.동점 이후는 이어지는 정수

결과는 점수 DESC로 낼 것!


2. 문제 풀이

윈도우 함수를 아신다면,
문제의 조건들만 봐도 윈도우 함수를 사용해야함을 알 것입니다.

윈도우 함수의 개념들은 이전 게시글에서 설명을 했으니,
여기서는 생략하겠습니다.

윈도우 함수에는 RANK() 관련한 문법들이 몇 개 있는데,
살펴보도록 하겠습니다.

※개념_1. 윈도우 함수의 RANK() 문법들

ROW_NUMBER()는 동점이어도 무조건 다른 연속적인 순위로 나타내고, RANK()는 동점이면 같은 순위,다음 순위는 건너뜁니다. 마지막으로 DENSE_RANK()는 동점이면 같은 순위이며, 다음 순위를 건너뛰지 않고 연속적으로 이어붙입니다.


그러면, 우리는 위 조건들을 봤을 때,
DENSE_RANK()를 사용하면 한번에 해결됨을 알 수 있습니다.
-> '동점은 같은 등수' & '동점 이후는 이어지는 정수(CONSECUTIVE)'

<최종 답안>

SELECT
    -- ID,
    SCORE,
    DENSE_RANK() OVER(ORDER BY SCORE DESC) AS 'RANK'
FROM SCORES;

※개념_2

위 AS 'RANK'에서 RANK는 SQL 예약어이므로, ``(백틱)으로만 감싸야합니다.

안 그러면 에러가 납니다.

->LEETCODE는 이렇게 SUBMIT을 해서 모든 테스트케이스에 다 통과하게 되면 이렇게 'ACCEPTED' 및 RUNTIME 시간을 알려줍니다.


#176번

1. 문제 소개

*테이블

EMPLOYEE(ID(PK), SALARY)

*문제

Write a solution to find the second highest distinct salary from the Employee table. If there is no second highest salary, return null (return None in Pandas).
->두번째로 높은 연봉(DISTINCT이니깐 중복 X의 의미인가?. 맞음.) 찾기. 없으면 NULL 반환


2. 문제 풀이

SELECT
    ID,
    SALARY,
    DENSE_RANK() OVER(ORDER BY SALARY DESC) AS 'SALARY_RANK'
FROM EMPLOYEE) 

일단 저는 위 #178번 문제와 같이 먼저 DENSE_RANK()로 구현을 해봤습니다.

그리고 여기서 서브쿼리로 감싸면 결과가 나오겠구나라고 생각했습니다.

SELECT
    SALARY AS 'SECONDHIGHESTSALARY'
FROM
(SELECT
    ID,
    SALARY,
    DENSE_RANK() OVER(ORDER BY SALARY DESC) AS 'SALARY_RANK'
FROM EMPLOYEE) AS T_1
WHERE SALARY_RANK = 2

근데 문제는 만약 2등이 없다면 NULL을 구현해야하는데,
이 NULL을 구하는 부분을 고민을 해봐도 어떻게 구현해야하는지 잘 몰라서 CLAUDE에게 물어봤습니다.

CLAUDE가 알려주길, 'IFNULL'이라는 문법이 있더라군요.

IFNULL로 '여기에 현재 쿼리' 부분에 제 서브쿼리를 넣고, 이 값이 아니라면 NULL로 처리하는 로직으로 구성되어 있었습니다.

<최종 정답 코드>

SELECT 
    IFNULL(
        (SELECT DISTINCT SALARY
        FROM (
            SELECT
                ID,
                SALARY,
                DENSE_RANK() OVER(ORDER BY SALARY DESC) AS 'SALARY_RANK'
            FROM EMPLOYEE) AS T_1
            WHERE SALARY_RANK = 2
        ),NULL)
     AS SecondHighestSalary

먼저 정답 코드를 공개하고 설명하도록 하겠습니다.

SQL문 구조가 평소와는 다르게 좀 독특해보일 것입니다.

메인 SELECT문에는 IFNULL을 통해 로직 구현을 시작합니다.

그리고 IFNULL안에는 말 그대로 IF+NULL 같이 로직이 이루어지는데, IF로 서브쿼리 부분이 만족하면 그 값을, 아니면 NULL을 반환합니다.

※정확한 IFNULL 설명

제가 위에서 IFNULL을 잘못 설명했습니다.

IFNULL은 말 그대로 'NULL인지 아닌지'를 판단하는 함수로,
NULL일시에는 '대체값'을 NULL이 아닐시에는 '값'을 리턴합니다.

서브쿼리 부분을 살펴보면,
2번의 서브쿼리로 이루어져있는데,
제일 안쪽의 서브쿼리는 제가 위에 작성한 쿼리문을 그대로 넣고,
이 의미는 SALARY_RANK = 2일 때의 ID,SALARY,DENSE_RANK()를 SELECT하는 절입니다.

그 다음 서브쿼리절에서는 조건에 따라 'DISTINCT SALARY' 또는 'NULL'을 선택하는 절입니다.
이 조건은 위에서 설명한 안쪽의 서브쿼리 WHERE절입니다.

다만 DISTINCT를 꼭 필수로 사용해야하는데,
이는 문제 조건에서 DISTINCT로 하라고 했기 때문입니다.

※자잘한 개념_3

DISTINCT 말고도 LIMIT 1으로 구현할 수 있습니다.
다만, 이 둘의 의미는 약간 다릅니다.

결과는 같습니다.

그리고 특이하게도 이 SQL문은 SELECT ~ AS로만 끝나고 FROM은 보이지가 않습니다.

이 이유는 다음과 같습니다.

※개념_4

그냥 가장 쉬운 방법은 그 상황에 맞게 이해를 하며 적용하며 되는 것입니다.

FROM이 필요한 경우는 내가 해당 테이블에서 해당 열을 가져오고 싶을 때 쓰는 것이고, FROM이 필요없는 경우는 테이블 참조 없이 그냥 값만 계산해도 될 때,

이렇게 쉽게 그 상황을 이해하면서 적용하면 될 거 같습니다.

->여기서 주의할 점은 AS SECOND~ 이렇게 저처럼 대문자로만 쓰면 오답처리됩니다. 대문자와 소문자를 구별해서 별칭(ALIAS)를 지칭하시길 바랍니다.


3. 마무리

이렇게 해서 이번에는 처음으로 LEETCODE에서 WINDOW FUNCTION MEDIUM 난이도 2문제를 풀어보았습니다.

EASY~MEDIUM 답게 어렵다기보다는
새로운 개념(IFNULL)을 알아가서 좋았습니다.

이번에도 제 긴 글을 읽어주셔서 감사합니다!! :) bb

profile
통합형 개발자. 기획부터 개발, 자동화까지. 문제를 구조적으로 이해하고, AI를 능동적으로 활용해 본질적인 해결책을 제시하는 사람입니다.

0개의 댓글