집 짓는 개발블로그
[프로그래머스] 노선과 평균 역 사이 거리 조회하기 (MySQL) 본문
https://school.programmers.co.kr/learn/courses/30/lessons/284531
문제 요약:
CONCAT, CONVERT(또는 CAST), SUM, AVG, ROUND 함수를 사용할 수 있냐를 묻는 문제다.
소요시간: ♾️
내 힘으로 못 풀었음. 생각지도 못한 포인트가 있는 문제.
1차 시도(실패)
SELECT ROUTE, CONCAT(CONVERT(ROUND(SUM(D_BETWEEN_DIST), 1), CHAR), 'km') AS 'TOTAL_DISTANCE',
CONCAT(CONVERT(ROUND(AVG(D_BETWEEN_DIST), 2), CHAR), 'km') AS 'AVERAGE_DISTANCE'
FROM SUBWAY_DISTANCE
GROUP BY ROUTE
ORDER BY TOTAL_DISTANCE DESC;
쭉 풀어놓고 바로 테스트 통과하길래 뿌듯해하고 있었다. 심지어 ORDER BY 다음에 alias를 써도 되나 잠깐 헷갈렸는데 역시 되네~! 하고 좋아했다. ^^
이대로 제출하면 오답 처리된다. 이유를 모르겠어서 프로그래머스 질문하기를 보다가 어떤 분이 설명해주신 정답을 찾았다.
오답 포인트
문제를 제대로 읽고 이해해야 한다.
문제에서는 분명 '총 누계 거리를 기준으로 내림차순 정렬' 하라고 했으니 순수한 총 누계 거리를 ORDER BY 뒤에 쓰는 게 맞다.
그런데 어떤 랜덤한 편견에 휩싸여서 아주 자연스럽게 TOTAL_DISTANCE를 기준으로 정렬해버린 것이다. ㅎㅎ TOTAL_DISTANCE가 무엇인가? 바로 문제의 요구에 따라 총 누계 거리를 1) 소수 셋째자리에서 반올림하고 2) 그걸 문자열로 바꾼 뒤 3) 'km'과 contatenate한 문자열이다.
그러니 이 쿼리를 실행시키면 본래의 총 누계거리가 아닌, 가공된 문자열이 기준이 되어버린다. 테스트케이스는 운이 좋게 통과한 것일 뿐인 것...
기업 코테에서도 이런 식으로 sql을 많이 틀렸을까 생각이 든다. 🫠
정답
SELECT ROUTE,
CONCAT(CONVERT(ROUND(SUM(D_BETWEEN_DIST), 1), CHAR), 'km') AS 'TOTAL_DISTANCE',
CONCAT(CONVERT(ROUND(AVG(D_BETWEEN_DIST), 2), CHAR), 'km') AS 'AVERAGE_DISTANCE'
FROM SUBWAY_DISTANCE
GROUP BY ROUTE
ORDER BY SUM(D_BETWEEN_DIST) DESC;
+ 이 문제에서 얻어가야 하는 포인트
1. ROUND -- 반올림
항상 헷갈리는 부분은 두 번째 인자가 무엇인지인데, 문제에서는 주로 '소수 몇 번째 자리에서 반올림해달라'는 요구사항이 나온다.
행동강령은 이렇다:
1) 문제를 확인하고, 요구사항대로 반올림하면 소수 몇 번째 자리가 마지막이 되는지 구한다. 예를 들어 셋째 자리에서 반올림하면 둘째 자리까지만 남을 것이다.
2) ROUND함수의 두 번째 인자는 이 '남은 자리수'가 된다.
예를 들어, 123.4567을 소수 셋째 자리에서 반올림하려면 다음과 같이 쓰면 된다.
ROUND(123.4567, 2)
2. CONVERT -- 타입 변환(캐스팅)
CONVERT(변환 전 값, 원하는 타입)
이렇게 쓰면 된다. 이 문제에서는 문자열로 바꿔서 concat하고 싶었기 때문에 CHAR로 변환했다.
MySQL에서는 str, string 등이 아니라 CHAR인 것도 기억해야 하는 포인트다. 타입변환 오래 안 하면 가끔 헷갈려서 STR.. 이런 거 쳐놓고 혼자 고민한다...
같은 용도로 CAST함수도 사용 가능하다.
CAST(변환 전 값 AS 원하는 타입) 이렇게 쓰면 되는데, 나는 CONVERT가 더 직관적이라 주로 사용한다. 순서만 잘 기억하면 된다.
변환 가능한 타입은 다음과 같다.
CHAR[(N)]
DATE
DATETIME
DECIMAL[(M [,D])]
SIGNED[INTEGER]
UNSIGNED[INTEGER]
TIME
JSON
NCHAR[(N)]
코딩테스트에서 많이 사용될 변환은 역시 DATE나 DATETIME인 것 같다.
CONVERT('20240624', DATE) -- 2024-06-24로 변환된다. 문자열이 아니라 20240624를 넣어도 된다.
DATETIME은 다음에 DATE_FORMAT을 정리하면서 다뤄야겠다. 지옥의 데이트포맷 너무 헷갈린다ㅎㅎ~
3. ORDER BY 뒤에 SELECT에서 붙인 Alias 써도 된다!
왜냐면 쿼리 실행 순서가 from - where - group by - select - order by - limit이기 때문이다. ORDER BY부터는 SELECT 이후 일이기 때문에 마음껏 사용해도 된다.
'MySQL' 카테고리의 다른 글
MySQL DATE_FORMAT 정리 (0) | 2024.06.27 |
---|---|
[프로그래머스] 분기별 분화된 대장균의 개체 수 구하기 (MySQL) - Alias와 "'따옴표'", MONTH, DAY, CASE-WHEN-THEN-ELSE-END (2) | 2024.06.27 |
[프로그래머스] 업그레이드 된 아이템 구하기 (MySQL) - INNER JOIN으로 NULL 바로 제거하기, EXISTS (0) | 2024.06.23 |
[프로그래머스] LV.3 숫자 게임 (Python) - deque (0) | 2024.06.22 |
[프로그래머스] 조건에 맞는 개발자 찾기 (MySQL) - EXISTS, 서브쿼리 (0) | 2024.06.22 |