본문 바로가기

열정가득한 개발자의 이야기/프로그래머스 문제

프로그래머스 PCSQL 4번 문제

안녕하세요

후.. 프로그래머스 PCSQL 4번 문제… 풀이를 가져와봤습니다.

진짜 죽는 줄 알았습니다.

문제부터 이해가 너무 어렵고, 너무 복잡했습니다. 

 

일단 문제는 아래와 같아요.

 

문제 요약 : 

간략하게 문제가 요약될지는 모르겠는데 해보겠습니다. 

문제의 내용을 딱! 간단하게 말씀드리면 각 ID당, 동일한 제출 순서의 정답 비율을 구하면 되는 겁니다. 

근데 테이블을 보시면 USER_ID 201번이 가장 밑에 또 나오는데, 이건 PROBLEM_ID가 다르기 때문에 처음 제출한 것으로 보아야 합니다. 

즉, PROBLEM_ID를 기준으로 제출 순서를 매겨야 한다는 뜻입니다. 

 

진짜.. 문제 너무 괴로워요.. 너무 헷갈려요.. 여전히 헷갈려요..

제가 쓴 SQL이 65 LINE정도 되고,, 거의 5시간 걸렸습니다.. 머리 쥐어뜯고 싶었어요..

심지어 모든 테스트 케이스를 통과하지 못해서 100점 만점에 37.5점 받았습니다.. 3개의 테스트만 톳과했.. 흑흑

그래도 전,,, 너무 만족합니다. 내리 5시간 정도 문제 푼 건 처음이었어요.

이거 난이도 너무한 거 아니냐고…

 

(수정 :  중복된 코드가 있어서 좀 줄였어요… 40 line 나왔습니다.. ㅎ… 중복코드도 찾아내고,, 나란 녀석 잘했다. 훗)

 

하여간 먼저 눈 돌아갈 거 같은 저의… SQL 보여드릴게요

WITH T1 AS (

    SELECT

        SS.USER_ID,

        SS.PROBLEM_ID,

        SS.TIMESTAMP,

        SS.SUBMITTED,

        SS.RNK,

        SS.CORRECT_ANSWER

    FROM (

        SELECT

            S.USER_ID,

            S.PROBLEM_ID,

            S.SUBMITTED,

            S.TIMESTAMP,

            P.CORRECT_ANSWER,

            ROW_NUMBER() OVER(PARTITION BY CONCAT(S.USER_ID, S.PROBLEM_ID) ORDER BY S.TIMESTAMP) AS RNK

        FROM

            SUBMISSIONS S

        INNER JOIN

            PROBLEMS P ON P.PROBLEM_ID = S.PROBLEM_ID

    ) AS SS

)

, GSAS( SELECT

        T1.RNK,

        COUNT(*) AS RATE

    FROM

     T1

    GROUP BY

        T1.RNK

    ), FINAS

    (SELECT  A.RNK ASFIRNK, COUNT(A.RNK) AS COUNT2 FROM T1 A

        JOIN PROBLEMS PB

        WHERE A.SUBMITTED = PB.CORRECT_ANSWER

        GROUP BY A.RNK

        ORDER BY A.RNK ASC

    )

SELECT FIN.FIRNK AS NTH_SUBMISSION, ROUND((FIN.COUNT2/GS.RATE) *100) AS CORRECT_RATE

FROM FIN

INNER JOIN GS

ON GS.RNK = FIN.FIRNK

 

 

이젠 SQL을 나눠서 설명드리겠습니다. 

 

WITH T1 AS (

    SELECT

        SS.USER_ID,

        SS.PROBLEM_ID,

        SS.TIMESTAMP,

        SS.SUBMITTED,

        SS.RNK,

        SS.CORRECT_ANSWER

    FROM (

        SELECT

            S.USER_ID,

            S.PROBLEM_ID,

            S.SUBMITTED,

            S.TIMESTAMP,

            P.CORRECT_ANSWER,

            ROW_NUMBER() OVER(PARTITION BY CONCAT(S.USER_ID, S.PROBLEM_ID) ORDER BY S.TIMESTAMP) AS RNK

        FROM

            SUBMISSIONS S

        INNER JOIN

            PROBLEMS P ON P.PROBLEM_ID = S.PROBLEM_ID

    ) AS SS

)

 

일단… 처음 with절 시작을 설명드릴게요.

먼저 FROM절에 SUB QUERY와 JOIN문과 ROW_NUMBER를 써서 RNK라는 걸 만들어줬습니다. 그래야 제출의 순서를 매길 수 있으니까요..

(아 여기서 주의할 점은 rank라는 sql함수가 있기 때문에 이름을 RANK라고 하면 오류가 뜹니다. 이걸 까먹고 그냥 진행하다가... 계속 오류 떠서 눈 뒤집혔었어요.. 호호호)

그래서 위의 사진과 같이 RNK를 보시면 각 ID와 PROBLEN_ID로 순서가 매겨진 것을 확인할 수 있습니다.  



 

GS AS( SELECT

        T1.RNK,

        COUNT(*) AS RATE

    FROM

     T1

    GROUP BY

        T1.RNK

    )

 

그다음 GS라는 임시 테이블을 만들어서 각 제출 순서에 몇 번을 제출했는지 구했습니다. 

음.. 말이 좀 이상한데, 예로 첫 번째 제출한 사람은 모두 4명이고, 2번째 제출한 사람은 3명, 마지막으로 제출한 사람은 1명 이렇게요.

 

이렇게 제출 순서와, 제출 순서에 몇 명이 제출했는지 모두 확인했습니다. 

이젠 제출 순서에 따른 정답 자의 수를 구하면 됩니다..



FIN AS

    (SELECT  A.RNK ASFIRNK, COUNT(A.RNK) AS COUNT2 FROM T1 A

        JOIN PROBLEMS PB

        WHERE A.SUBMITTED = PB.CORRECT_ANSWER

        GROUP BY A.RNK

        ORDER BY A.RNK ASC

    )

 

이렇게 FIN이라는 임시테이블에 각 제출 순서 당 몇 문제를 맞혔는지 나오는 테이블을 만들었습니다. 

 

그럼 모든 준비물이 준비되었으니,, 정답률만 구하는 SELECT 문을 만들어 주면 됩니다. 

SELECT FIN.FIRNK AS NTH_SUBMISSION, ROUND((FIN.COUNT2/GS.RATE) *100) AS CORRECT_RATE

FROM FIN

INNER JOIN GS

ON GS.RNK = FIN.FIRNK

ORDER BY NTH_SUBMISSION

 

정답률은 100을 곱하고 소수점 1자리에서 반올림을 하여 정수로 나타내 주면 됩니다.

그래서 ROUND함수를 썼고 소수점 첫자리는 0이면서 DEFAULT이기 때문에 아무 값도 넣어주지 않았습니다. 



이렇게.. 해서… 37.5점 받았어요…

전.. 만족합니다..

너무 어지러워요..

너무 한 거 아니냐고.. 문제..

이거 마치 초등학교 수학책풀다가 함수 하라고 하는 것 같아요..

프로그래머스 SQL LV5까지 다 풀었는데 이렇게까지 안 나오잖아요..

마음에 준비 좀 할 수 있게 해 주지…

 

그래도 포기하지 않고 끝까지 물고 늘어진 내가 너무 좋네요

내일 pcsql진행되는데.. 정말 너무 걱정이 되네요.. 목표는 2문제 맞히기입니다.. 흑흑