본문 바로가기

TIL

[240125] SQL: 코드카타 115 & 파이썬: 코드카타 24

[SQL 코드카타]

1341. Movie Rating

https://leetcode.com/problems/movie-rating/

 

1) 어떤 문제가 있었나

평점이  가장 높은 영화 '제목'과 가장 많은 점수를 부여한 '사람 이름'을 하나의 열에 추출하는 문제

값이 같으면 제목 및 이름 오름차순 기준으로 정렬하여 앞에 오는 것으로 추출

주어진 3개의 테이블을 하나로 join이 좋을지, 2개씩 join하면 속성이 상이한 최종값을 어떻게 하나의 열로 추출할지 고민

 

2) 내가 시도해본 건 무엇인가

movie, user, MovieRaing 3개를 모두 조인해보고 rank 함수 등 적용해보았으나 실패

2개의 별도 쿼리문 union 필요하다는 것을 깨닫고 with 절과 윈도우 함수 활용해 임시 테이블 생성하여 결과값 도출 


3) 어떻게 해결했나 

too..long..

with movie_table as (select r.movie_id,  
                           title,                               
                           avg(rating) avg_rating, 
                           rank() over (order by avg(rating) desc, title asc) movie_rank
                        from MovieRating r
                        inner join Movies m on r.movie_id = m.movie_id
                        where date_format(created_at, '%Y-%m') = '2020-02'
                        group by r.movie_id), 
      user_table as (select r.user_id,
                            name,
                            sum(r.rating) sum_rating,
                            rank() over (order by sum(r.rating) desc, name asc) user_rank
                    from MovieRating r
                    inner join Users u on u.user_id = r.user_id
                    group by r.user_id) 

select title results      
from movie_table
where movie_rank = 1
union 
select name results      
from user_table
where user_rank = 1

 

#다른 사람 풀이
#first_value 윈도우 함수 활용

SELECT DISTINCT FIRST_VALUE(u.name) OVER(ORDER BY COUNT(r.movie_id) DESC, u.name ASC) AS results
FROM Users AS u 
LEFT JOIN MovieRating AS r N u.user_id=r.user_id
GROUP BY u.user_id
UNION ALL
SELECT DISTINCT FIRST_VALUE(m.title) OVER(ORDER BY AVG(r.rating) DESC, m.title ASC) AS results
FROM Movies AS m join MovieRating AS r
ON m.movie_id=r.movie_id
WHERE r.created_at BETWEEN '2020-02-01' AND '2020-02-29'
GROUP BY m.movie_id


4) 무엇을 새롭게 알았나

- 윈도우 함수 적용할 그룹과 본 쿼리 그룹이 같을 경우, parition by 대신 본 쿼리에 group by 설정하면 됨 

└ 본 쿼리는 A카테고리, 윈도우함수 기준은 B카테고리일 경우 group by와 partition by에 따로 적용하면 될듯 

- rank = 1 or row_number = 1 조건은 First_value 함수로 대체 가능할 수도


[파이썬 코드카타]

서울에서 김서방 찾기
https://school.programmers.co.kr/learn/courses/30/lessons/12919

1) 어떤 문제가 있었나

문자열 배열에서 "Kim"의 위치를 찾아 f-string 형으로 답을 제출하는 문제 

 

seoul = ["Jane", "Kim"]

return  = "김서방은 1에 있다"

 

2) 내가 시도해본 건 무엇인가

seoul 리스트에서 원소를 하나식 빼면서 "Kim"이 아니면 1을 추가하고, 마지막에 -1 처리(파이썬은 0부터 시작하므로?)

> 제출 결과: 정확성이 21.4로 실패 (오답)

> 원인 파악:  "Kim" 뒤에 다른 이름이 나오면 그것도 카운팅해서 제대로된 위치값이 안 나옴 

def solution(seoul):
    answer = 0 
    for i in seoul:
        i != "Kim"
        answer += 1
    return (f'김서방은 {answer-1}에 있다')


3) 어떻게 해결했나

def solution(seoul):
    answer = list(enumerate(seoul)) #seoul 리스트 값 인덱스 처리
    for i in answer:
        if i[1] == "Kim":   
            return (f'김서방은 {i[0]}에 있다') #'Kim'인 인덱스값 반환
            
#위 오답에서 문제 해결한 정답 
def solution(seoul):
    answer = 0 
    for i in seoul:
        if i != "Kim":
            answer += 1
        else:              #kim을 찾으면 멈추도록 
            break
    return (f'김서방은 {answer}에 있다') #마지막 Kim은 카운팅 안 하니까 
                                       #파이썬 순서 0으로 시작하는 것 별도 처리 안 해줘도 됨


4) 무엇을 새롭게 알았나

- enumerate() 

└ 순서가 있는 자료형(list, set, tuple, dictionary, string)에 인덱스를 붙여주는 메소드

사용 후 리스트로 한 번 감싸줘야 함 ex. answer = list(enumerate(seoul)) 

보통 0으로 시작하며, start = n 으로 시작값 지정도 가능