개강의 달이라는 3월, 난 이런저런 일들이 발생했다. 먼저 주차해둔 차가 뺑소니를 당했다. 심지어 블랙박스가 저장이 되지 않아 이틀 동안 분노의 양치질을 했지만, 어제 가해차주에게 연락을 받아 오늘 정비소에 입고시켰다. 물론 덕분에 평소에 타보고 싶었던 토레스를 렌트 받았으니, 좋은게 좋은 거 아닐까?
어제는 예비군으로 별로 뭔가를 하지 못해, TIL을 작성하지 못했다. 그러니 오늘의 TIL을 열심히 써보도록 하자.
다른 건 몰라도 매일 꾸준한 코드카타를 하는 건 나에게 있어 타협할 수 없는 일과다. 이것마저 안 한다면 스스로를 금수라고 생각하고, 심바를 내 침대에서 자게 할 꺼라고 스스로 약속했다. 오늘은 SQL 코드카타 3개와 알고리즘 코드카타 4문제를 풀었다.
40번 후반에서 급격히 높아진 난이도에 나는 다리를 떨면서 문제를 풀 수밖에 없었다.
48번 문제
REST_INFO 테이블에서 음식종류별로 즐겨찾기수가 가장 많은 식당의 음식 종류, ID, 식당 이름, 즐겨찾기수를 조회하는 SQL문을 작성해주세요. 이때 결과는 음식 종류를 기준으로 내림차순 정렬해주세요.SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES FROM ( SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES, RANK() over (partition by FOOD_TYPE order by FAVORITES DESC) as A FROM REST_INFO ) as a WHERE A = 1 ORDER BY FOOD_TYPE DESC
오늘 코드카타 문제들의 핵심은 RANK 함수를 얼마나 잘 쓰느냐에 달려있다. 음식종류를 기준으로, 각 기준에서 즐겨찾기(FAVORITE)을 가장 많이 받은 식당들을 각각 뽑아내는 것이 우선이다. 따라서 인라인 뷰 서브쿼리에서 RANK 함수를 사용해 순위를 뽑아줘야 했다.
개인적으로는 왜 partition에 DESC를 써야하는지 이해가 가질 않는다. 어차피 RANK를 통해 순위를 매긴다면 그 나열은 FAVORITE 수치가 가장 높은 식당에서 낮은 식당으로 갈텐데, 왜 DESC를 써야하는 걸까? 내일 튜터님께 질문을 드려야겠다. 그걸 제외하면 나머지 부가 조건들은 평탄했다.
49번 문제
FOOD_PRODUCT 테이블에서 식품분류별로 가격이 제일 비싼 식품의 분류, 가격, 이름을 조회하는 SQL문을 작성해주세요. 이때 식품분류가 '과자', '국', '김치', '식용유'인 경우만 출력시켜 주시고 결과는 식품 가격을 기준으로 내림차순 정렬해주세요.# 정답 풀이 SELECT CATEGORY, price MAX_PRICE, PRODUCT_NAME FROM ( SELECT PRODUCT_ID, PRODUCT_NAME,PRODUCT_CD, CATEGORY, PRICE,RANK() over(partition by CATEGORY order by PRICE DESC) as PR FROM FOOD_PRODUCT WHERE CATEGORY in ('과자', '국', '김치', '식용유') ) as a WHERE PR = 1 ORDER BY MAX_PRICE DESC
# 내 틀린 풀이 SELECT CATEGORY, MAX(price) as MAX_PRICE, PRODUCT_NAME FROM ( SELECT PRODUCT_ID, PRODUCT_NAME,PRODUCT_CD, CATEGORY, PRICE,RANK() over(partition by CATEGORY order by PRICE DESC) as S FROM FOOD_PRODUCT GROUP BY CATEGORY ) as a where S=1 and CATEGORY in ('과자', '국', '김치', '식용유') GROUP BY CATEGORY ORDER BY PRICE DESC
오답노트가 확실히 필요한 문제다.
우선 인라인 뷰 서브쿼리에서 GROUP BY를 쓴 것이 첫 번째 실책이다. 이 문제는 총합을 산출해내는 문제가 아니다. 이 문제는 카테고리가 아니라, 가격이 가장 비싼 '식품'의 데이터를 뽑아내는 것이며, 카테고리는 그걸 나누는 기준에 불과하다.
MAX(price)가 답이 틀린 이유 중 하나인지는 확실치 않으나, 적어도 틀린 접근이라는 것에는 틀림이 없다. 이미 RANK로 PRICE의 순위를 나눈 순간 MAX로 최댓값을 구하는 것은 의미가 없기 때문이다.
테스트 결과 카테고리 조건은 서브쿼리에 넣든 외부 커리에 넣든 상관이 없었다.
50번 문제
FOOD_PRODUCT와 FOOD_ORDER 테이블에서 생산일자가 2022년 5월인 식품들의 식품 ID, 식품 이름, 총매출을 조회하는 SQL문을 작성해주세요. 이때 결과는 총매출을 기준으로 내림차순 정렬해주시고 총매출이 같다면 식품 ID를 기준으로 오름차순 정렬해주세요.SELECT DISTINCT a.PRODUCT_ID, a.PRODUCT_NAME, (a.PRICE*SUM(b.AMOUNT)) TOTAL_PRICE FROM ( SELECT PRODUCT_ID, PRODUCT_NAME, PRICE FROM FOOD_PRODUCT ) as a LEFT JOIN ( SELECT PRODUCT_ID, PRODUCE_DATE, AMOUNT FROM FOOD_ORDER ) as b on a.PRODUCT_ID = b.PRODUCT_ID WHERE DATE_FORMAT(PRODUCE_DATE, ('%Y-%m')) = '2022-05' GROUP BY a. PRODUCT_ID ORDER BY TOTAL_PRICE DESC, a.PRODUCT_ID ASC
문제가 어렵다기보다는 조인으로 만든 임시 테이블의 쿼리끼리 연산을 진행해야 하거나, DATE_FORMAT을 이용한 날짜 조건을 적용하는 등, 고려해야할 조건이 좀 많아서 그것을 오류 없이 적용하기 위해 신경을 많이 써야 했다. 적어도 JOIN 과정에서 각 테이블에 조건을 적용할 필요는 없었으니, 오히려 오늘 문제 중 가장 쉬웠다고 할 수 있겠다.
오늘의 후기
개인적으로는 RANK 함수이 어떻게 발동되는지, 그 성질이 무엇인지에 대해 조금 더 알고 싶어졌다. 어디 인도인 강의나 찾아봐야겠다.
다른 사람들의 풀이를 보던 중 AND 메서드를 많이 사용하는 것 같다. 기본적인 메서드 같은데 난 모르는 것이니, 이것도 좀 공부가 필요해보인다.
어떤 문제를 풀 때 가장 싫은 것은 접근조차 못하고 시간을 버리는 일이다. 오늘 처음으로 파이썬 코드카타에 도전하면서 그 느낌이 들었다. 대체 어떻게 첫발을 띄어야 할지조차 답이 안 나오는 것이 너무 무기력했다.
9번 문제
정수 n이 주어질 때, n이하의 짝수를 모두 더한 값을 return 하도록 solution 함수를 작성해주세요.def solution(n): answer = 0 for i in range(2, n+1, 2): if i % 2 ==0: answer += i return answer
접근을 못한 가장 큰 이유는 def라는, 함수 형태 개념이 전혀 떠오르지 않았기 때문이 컸다. 당장
def solution(n): answer = 0 return answer
이렇게 써있는데 뭘 어쩌라는 건지 감이 오지 않았다. 다행히 친절한 우리 챗대리와 함께 함수 정의의 개념을 공부해보려했지만, 챗대리조차 나의 무지함을 씻어내지는 못했다. 그리고 왜 답이 저거인지도 솔직히 모르겠다. 이건 내일 튜터님을 찾아가서 울면서 상담을 받아봐야겠다.
10번 문제
정수 배열 numbers가 매개변수로 주어집니다. numbers의 원소의 평균값을 return하도록 solution 함수를 완성해주세요.def solution(numbers): answer = sum(numbers) / len(numbers) return answer
설마 이렇게 쉬울까 하고 써본 게 정답이었다. 평균을 구하는 건 강의 예제로도 너무 많이 나와서, 저 형태 자체로도 이제는 외울 지경에 이르렀다.
11번 문제
정수 num이 짝수일 경우 "Even"을 반환하고 홀수인 경우 "Odd"를 반환하는 함수, solution을 완성해주세요.def solution(num): if num%2==0: answer = "Even" else: answer = "Odd" return answer
10번 문제를 풀고 보니, 간단한 함수의 형태와 구조를 대강 알게 되었고, 그에 맞게 작성해본 결과 정답이었다. 이 문제는 함수 뿐 아니라 기본적으로 조건문을 어떻게 작성해야 하는지에 대한 기초 이해를 필요로 하는 문제였다. 그거 하나는 잘 외워서 다행이다. 콜론을 빼먹지 않도록 조심하자.
12번 문제
정수를 담고 있는 배열 arr의 평균값을 return하는 함수, solution을 완성해보세요.def solution(arr): answer = sum(arr)/len(arr) return answer
10번을 풀었는데 이걸 못 풀 수가 없다. 너무 똑같아서 솔직히 이게 맞나 싶었는데, 차라리 다른 답을 찾아보는 것이 낫겠다 생각해서 다른 답안들을 살펴보았다.
if len(list) == 0: return 0 else: return sum(list) / len(list)
return reduce(lambda x, y : x + y, list) / len(list)
일단 람다에 대한 강의를 내일 볼 예정이기 때문에, 이 풀이가 왜 맞는지도 내일 알 수 있게 되길 바랄 뿐이다. 개인적으로는 if 조건문을 사용한 코드가 맘에 들었다. 물론 문제에는 arr가 1 이상의 정수라는 점이 표기되어있지만, 그것이 없이 정수의 평균을 구하는 문제였다면, 0을 개수로 고려해 분모에 1을 더하는 불상사를 방지하기 위한 좋은 조건문이었다고 생각한다.
오늘 파이썬 4주차 함수 강의를 듣고 정리했다. 코드카타를 손도 못 댔던 이유가 함수의 형태에 대한 무지였음을 감안한다면, 참으로 시의적절한 강의가 아닐 수 없었다. 여기까지 앞서본 것입니까, 튜터님...?
오늘 배운 내용을 여기다 옮기는 것은 의미가 없다고 생각한다. 다만 사전 캠프 당시 들었던 파이썬 강의에 이번 정규 캠프 파이썬 강의 내용을 덧붙이면서 정리를 하고 있는데, 내가 놓친 내용이 많다는 것을 알게 되었다. 함수의 형태와 작동 원리, 매개변수 개념 같은 것은 사전 캠프 때는 알지도 못하고 넘어갔던 내용들이기 때문이다. 개념과 원리만 잘 잡아놓는다면 나머지는 기술과 반복의 영역이니, 치밀하게 정리해서 요긴하게 써먹도록 하자.
하지만 여전히, 파이썬은 나에게 공포의 대마왕이다. 다만 SQL 쿼리 작성과 파이썬 코드 작성이 같은 결과물을 만들더라도 완전히 다른 접근법이라는 걸 알게 되었다는 점은 튜터님도 말씀하셨듯, 좋은 깨달음이라고 생각한다.
무시하던 자격증 강의도 공부를 시작하기로 마음 먹었다. SQLD와 ADSP 둘 다 5월에 시험이 있고, 이 캠프는 6-7월까지 진행이 될 예정이니, 하반기 채용 시즌을 놓치지 않기 위해선 지금 개념 정리를 끝내놓고 4월 한달 빡시게 준비해서 시험을 치루는 것이 낫겠다.
어차피 개념 정리만 잘 잡아놓으면 1달은 기출이나 문제은행으로 신나게 풀면 되는 것이 자격증 시험이니, 강의가 좀 많더라도 망설임 없이 신나게 필기를 해보도록 하자.
부트캠프가 짧은 기간에 빠른 성장을 노린다는 특성을 감안하면, 아마 앞으로는 지금보다 더 많은 것들이 한 번에 진행될 것임은 분명하다. 다음주 주말에는 데이터 분석가로 일하는 친구와 커피챗 시간을 가지기로 했으니, 한 주 동안 궁금한 점들을 정리해봐야겠다.
오늘 느낀 점 중 하나는, 우리 모두가 불안함을 느끼고 있다는 것이었다. 내가 지금 잘 하고 있는지, 남들은 왜 나보다 더 잘하는 것 같은지, 그런 질문들이 머릿속에서 울리면서 점점 커지면, 남는 건.그 질문에 답할 수 없는 무기력한 나 뿐이다.
하지만 이건 경쟁이 아님을 잊지 말자. 부트캠프에서 이겨야할 것은 불안감과 그로부터 비롯되는 못난 '나' 뿐이다. 무언가 오래 걸렸다면 그거대로 배운 것이 있을 것이고, 너무 빨리 술술 풀렸다면 그거대로 놓치는 것이 있을 터, 그저 하루에 배운 것들을 놓치지 않게 노력하는 것만으로도 의미가 있다고 믿는다.
오늘 아침 갑자기 전화한 내 친구가 나에게 해준 이야기로 TIL을 마무리한다.
헤맨 만큼 내 땅이다.