본문 바로가기

SQL - Mysql & Oracle/SQL 실전 코딩 테스트

[MySQL] Hackerrank - SQL Project Planning 문제 풀이 해설

반응형

오늘 풀어보면서 공부할 문제는 Hackerrank에서 출제한 SQL Project Planning이다. 이 문제를 풀 때 개인적으로 Exists문을 통해서 풀어 냈고, 이 과정에서 배운 것을 공유하고자 한다. 

 

목차

1. 문제 출처 및 소개

2. Exists문을 통한 문제 풀이

3. Lesson Learned

     

    1. 문제 출처 및 소개

     

    SQL Project Planning 해설
    SQL Project Planning 해설

     

    • 문제의 출처: URL
    • 문제의 요구 조건 정리
      • 모든 프로젝트의 시작일과 종료일을 호출하는 것
      • 정렬 순서는 프로젝트 기간을 기준으로 오름차순으로 할 것
    • 문제의 특이사항 정리 
      • 모든 Task의 시작일과 종료일은 1일로 제한
      • Task의 종료일과 Task의 시작일이 겹치면 그것은 같은 프로젝트

     

    여기서 문제의 핵심은 Task에 부여되어 있는 시작일과 종료일을 어떻게 전처리를 하는가에 있다. 더 자세한 풀이는 아래의 영역을 참고하기를 바란다. 

     

     

     

    2. Exists문을 통한 문제 풀이

     

    문제 풀이 공략은 바로 연속되는 일자를 어떻게 처리하는가에 있다. 그래서 첫 번째 단계는 시작일과 종료일을 서로 분기 처리하는 것이다. 그 다음에는 프로젝트의 시작일과 종료일은 겹치면 안 되기 때문에 Full Join을 시켜 준 뒤에 고유한 값을 알아내면 될 것이다. 자세한 과정은 아래의 코드 설명을 참고하기를 바란다. 

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    SELECT t1.start_date
        , MIN(t2.end_date)
    FROM (
        SELECT a.start_date
        FROM Projects a 
        WHERE 1 = 1
            AND NOT EXISTS (
                SELECT a2.end_date
                FROM projects a2
                WHERE a2.end_date = a.start_date
            )
    ) t1
    , (
        SELECT b.end_date
        FROM Projects b
        WHERE 1 = 1
            AND NOT EXISTS (
                SELECT b2.end_date
                FROM projects b2
                WHERE b2.start_date = b.end_date
            )
    ) t2
    WHERE 1 = 1
        AND t1.start_date < t2.end_date
    GROUP BY t1.start_date
    ORDER BY DATEDIFF(t1.start_date, MIN(t2.end_date)) DESC, t1.start_date ASC;
     
    cs

     

    • 문제 풀이 공략
      • Step1. 시작일과 종료일을 서로 다르게 구분한다.
        • Subquery에서 이를 수행했고, 시작일과 종료일이 겹치는 기간이 있으면 그것은 Task 단위의 데이터이고 프로젝트 단위가 아니기 때문에 제거해야 한다.
        • 그래서 Subquery문 내에서 Exists문을 통해 상호배타적인 시작일과 종료일을 불러왔다.
      • Step2. Full Join을 통해 가능한 모든 가능한 경우의 수를 불러온다.
        • FULL JOIN을 하는 가장 간단한 방법 중 하나는 단순히 Table을 2개 호출하면 된다.
        • 다만, 이 방법은 메모리를 많이 쓰기 때문에 실무용이라기보다는 문제풀이 방법에 가깝다.
      • Step3. Where절과 GROUP BY 를 통해 데이터를 전처리한다.
        • Full Join을 하게 되면 모든 경우의 수가 나타나기 때문에 정답을 위한 전처리를 해야 한다.
        • 첫 번째는 where 절을 통해 시작일 >= 종료일인 에러 케이스는 제거한다.
        • 두 번째는 MIN(종료일)일 선택하게 되면, 프로젝트 시작일과 가장 가까운 종료일만 불러오게 된다. 이렇게 하게 되면 문제에서 요구하는 프로젝트의 시작일과 종료일을 찾을 수 있다는 점이다.
      • Step4. 문제에서 요구한 정렬 순서를 맞춘다. 

     

     

     

     

     

    3. Lesson Learned

     

     

    이 문제는 개인적으로 많은 주제에 대해서 공부를 할 수 있었다. 그 중에서 다른 문제 풀이에도 활용할 수 있을만한 주제에 대해서 간단히 오답노트를 기록하고 공유하도록 하겠다. 

     

    ✅ Full Join을 하는 방법

    Full Join을 하는 방법은 Join문을 써서 할 수도 있지만, 간단하게 Table 2개를 호출하면 된다. 하지만 이 방법은 위에서도 서술하였듯이 시공간 복잡도가 불필요하게 올라가는 단점이 있다. 따라서 이 방법은 실무나 문제의 성격에 따라 활용을 할 때 단점으로 작용할 수도 있다.

     

     

    ✅ Exists 문을 통한 데이터 제어

    사실 이 것은 IN을 통해서 해결할 수도 있었지만, 연습을 한다는 차원에서 Exist문을 활용하였다. 이 함수는 실무에서도 활용도가 높으니 공부해두는 것을 추천한다. 

     

     

    ✅ GROUP BY를 통한 데이터 전처리

    GROUP BY는 보통 집계를 하기 위해서 쓰는 경우가 많다. 하지만 이 문제를 통해서 불필요한 데이터를 제거하기 위해서 집계함수를 활용할 수도 있다는 스킬을 배웠던 것 같다. 

     

     

    반응형