Sparta/CODEKATA

[250923] 스파르타코딩 본캠프 36일차

junecho 2025. 9. 23. 12:08

💥  CODEKATA                                                                                                           

~ 98문제

 

오늘의 코드카타 후기 : WITH는 신이야

그리고 98번을 97번인줄 알고 풀어서 그냥 한 문제 더 풀었음 ㄱ-

 

 

 

97) Immediate Food Delivery II

# 1차 코드
SELECT ROUND(SUM(a.tf) / (SELECT COUNT(DISTINCT customer_id) FROM delivery), 2)*100 AS immediate_percentage 
FROM (
    SELECT 
        IF(MIN(order_date) = customer_pref_delivery_date, 1, 0) AS tf
    FROM delivery
    GROUP BY customer_id
) a

⇒ ❌

또 서버 테스트에서 틀림 하 ㄱ-.............

SUM(a.tf) 가 15가 나와야 하는데 대체 왜 자꾸 12가 나오는거지 이해 불가임;;

지피티는 FROM절 서브쿼리에서 또 WHERE 서브쿼리 쓰라는데 왜 쓰는지 이해불가

GROUP BY 랑 MIN으로 최초 주문 날짜 구했자나....? 왜 굳이 WHERE로 구해야지 정답인거지

아~~ 지피티 왈 "이 방식은 고객별 최소 주문일의 값만 알 뿐, 그 주문일에 연관된 customer_pref_delivery_date은 정확히 짝지어지는 것이 아님"

이라네 아하 맞네!

 

# 2차 코드
SELECT  ROUND(SUM(a.tf)*100 / (SELECT COUNT(DISTINCT customer_id) FROM delivery), 2) AS immediate_percentage 
FROM (
    SELECT IF(MIN(order_date) = MIN(customer_pref_delivery_date), 1, 0) AS tf
    FROM delivery
    GROUP BY customer_id
) a

⇒ ⭕

헤헷 나의 신 WITH님 없이 풀어보았습니다 우하핛

지피티는 FROM 절에서 GROUP BY 안쓰고 WHERE에다가 또 서브쿼리 웅앵~하는거 알려줬는데,

응 뭔 소린지 모르겠어 내 맘대로 살 거야 말리지 마 난 특별하니까 YEAH

 

 

 

 

98) Game Play Analysis IV

# 1차 코드
SELECT ROUND((COUNT(DISTINCT a1.player_id)) / (SELECT COUNT(DISTINCT player_id) FROM activity), 2) AS fraction
FROM activity a1 JOIN activity a2 ON DATEDIFF(a1.event_date, a2.event_date) = 1 AND a1.player_id = a2.player_id
WHERE a1.event_date > a2.event_date

⇒ ❌

케이스는 통과되는데, 서버 테스트에서 통과가 안됨

아무리 봐도 어디가 틀린지 모르겠어서 지피티한테 물어봄

답은 "첫 로그인 다음 날 재로그인이 핵심"

 

# 2차 코드
SELECT ROUND((COUNT(a1.player_id)) / (SELECT COUNT(DISTINCT player_id) FROM activity), 2) AS fraction
FROM activity a1 JOIN activity a2 ON DATEDIFF(a1.event_date, a2.event_date) = 1 AND a1.player_id = a2.player_id
WHERE a1.event_date > a2.event_date
GROUP BY a1.player_id
HAVING DATEDIFF(MIN(a1.event_date), MAX(a2.event_date)) = 1

⇒ ❌

ㅇㅣ렇게 짜니까 id별로 fraction이 나와서 에바...그룹바이 쓰면 안될 것 같은데, having은 필요함

집계함수를 써서 첫 로그인이날 다음날 로그인의 차이가 1인걸로 구하고 싶음

WHERE 에다가 MIN MAX 쓰기엔 WHERE절 자체에서는 집계함수를 못써서 안됨 어케해야할까

 

# 3차 코드
SELECT ROUND(IFNULL(SUM(a.cnt), 0) / (SELECT COUNT(DISTINCT player_id) FROM activity), 2) AS fraction
FROM (
    SELECT 
        player_id, MIN(event_date) AS mindate, MAX(event_date) AS maxdate, 
        DATE_ADD(MIN(event_date), INTERVAL 1 DAY) nextdate, COUNT(DISTINCT player_id) AS cnt
    FROM activity
    GROUP BY player_id
    HAVING maxdate = nextdate
) a

⇒ ❌

와 진짜 모르겠다 어디가 틀린거 WITH 안쓰고 최대한 효율적으로 짜보려고 하니까 머리 터지겠음

서버테스트 결과가 0이 나와 왤까 아~~~

또 지피티한테 물어봄

“플레이어가 3월1일, 3월2일, 3월4일에 로그인했을 때, maxdate는 3월4일입니다.

그런데 nextdate는 3월2일(3월1일 + 1일)이고, HAVING maxdate = nextdate 조건은 만족하지 않으므로

이 플레이어는 누락됩니다.” 라고 함 아…max로 nextday를 구하면 안되는구나

 

# 4차 코드
WITH first AS (
    SELECT 
        player_id, event_date, MIN(event_date) AS firstdate, DATE_ADD(MIN(event_date), INTERVAL 1 DAY) AS nextday, 
        COUNT(DISTINCT player_id) AS cnt
    FROM activity
    GROUP BY player_id
)

SELECT ROUND(COUNT(DISTINCT a.player_id) / (SELECT COUNT(DISTINCT player_id) FROM activity), 2) AS fraction
FROM activity a JOIN first f ON a.player_id = f.player_id AND a.event_date = f.nextday/

⇒ ⭕

호호 GG치고 WITH 쓰기 ㅎㅎ

역시 WITH는 신이야

자 이제 효율 1등 쿼리 탐방ㄱㄱ

 

 

# 효율 1등코드
SELECT ROUND(AVG(b.event_date IS NOT NULL), 2) fraction
FROM (
    SELECT player_id, MIN(event_date) event_date FROM activity GROUP BY player_id
    ) a LEFT JOIN activity b ON a.player_id = b.player_id
    AND DATEDIFF(a.event_date, b.event_date) = -1;

아 젠장~~! 내가 1차로 짰던 코드에서 좀만 수정하면 됐네 ㄱ-…………………………………………..

우울따