<문제 설명>
어느 한 게임에서 사용되는 아이템들은 업그레이드가 가능합니다.
'ITEM_A'->'ITEM_B'와 같이 업그레이드가 가능할 때
'ITEM_A'를 'ITEM_B' 의 PARENT 아이템,
PARENT 아이템이 없는 아이템을 ROOT 아이템이라고 합니다.

(중략)....

 

<문제>
아이템의 희귀도가 'RARE'인 아이템들의 모든 다음 업그레이드 아이템의 아이템 ID(ITEM_ID), 아이템 명(ITEM_NAME), 아이템의 희귀도(RARITY)를 출력하는 SQL 문을 작성해 주세요. 이때 결과는 아이템 ID를 기준으로 내림차순 정렬해 주세요.

 


 

 

처음에 대충 생각하고 접근했더니 원하는 정답을 얻어내기 어려웠던 문제입니다!

 

다시 정신을 집중하고, RIGHT 조인과 서브쿼리를 이용해서 문제를 바로 해결했어요.

 

제가 풀이한 방법을 설명해 보겠습니다.



https://school.programmers.co.kr/learn/courses/30/lessons/273711

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 


 

 

먼저 아이템의 희귀도가 'RARE'인 아이템들을 뽑아내서 시각화해 봅니다.

SELECT * FROM ITEM_INFO WHERE RARITY = 'RARE'

 

우리는 이 4개의 아이템들의 다음 업그레이드 아이템을 찾아야 합니다. 이를 위해서는 ITEM_TREE 테이블을 확인해 보아야 해요.

 

 

ITEM_TREE 테이블을 보고 직관적으로 이해하기가 어려웠어요. 딱 봤을 때 구조가 한눈에 들어오지 않았습니다. (쉽게 보이시는 분이 계시다면.... 멋지십니다! 따봉!)

 

 

그래서 이렇게 간단히 그래프를 그려 봤더니 쉽게 이해가 되었습니다. 우리가 구한 RARE 아이템은 0, 1, 3, 4였어요. 이 아이템들의 다음 업그레이드 아이템은 (0으로부터) 1, 2번 아이템 + (2로부터) 3, 4번 아이템 => 총 1, 2, 3, 4번 아이템이 해당됩니다. 이해가 되셨을까요?

 

그렇다면 일반화된 쿼리문으로 작성하려면 어떻게 해볼 수 있을까요? 우선 우리가 구한 RARE 아이템 0, 1, 3, 4가 부모가 되는 아이템, 즉 0, 1, 3, 4의 자식 아이템을 찾아야 해요. 이를 위해서 ITEM_TREE 테이블의 PARENT_ITEM_ID와, ITEM_INFO 테이블의 ITEM_ID가 동일한 부분을 연결해 주면 됩니다.

 

SELECT * FROM ITEM_INFO I
	RIGHT JOIN ITEM_TREE T
	ON I.ITEM_ID = T.PARENT_ITEM_ID
WHERE RARITY = 'RARE'

 

1) ITEM_INFO 테이블에서 RARITY가 'RARE'에 해당하는 아이템 중에서,

2) 그 아이템이 ITEM_TREE 테이블에 있는 어떤 놈의 PARENT_ITEM_ID에 해당한다면,

3) 그 놈들을 모두 뽑아내봐요.

 

라고 명령한 것과 같습니다. 그럼 위와 같이 결과를 시각화할 수 있는데요. 여기서 우리에게 필요한 것은 무엇일까요?

 

 

우리한테 필요한 것은 저기 저 1, 2, 3, 4번 아이템 번호밖에 없어요. T 테이블(ITEM_TREE)의 ITEM_ID만 뽑아내 주면 됩니다. SELECT 뒤에만 간단하게 바꾸어 줘 봅시다.

 

SELECT T.ITEM_ID FROM ITEM_INFO I
        RIGHT JOIN ITEM_TREE T
        ON I.ITEM_ID = T.PARENT_ITEM_ID
WHERE RARITY = 'RARE'

 

 

이제 우리가 원하는 아이디를 뽑아냈으니, 이 테이블을 서브쿼리로 기존의 ITEM_INFO 테이블과 조인해 주면 끝입니다!

 

SELECT X.ITEM_ID, I.ITEM_NAME, I.RARITY
FROM (SELECT T.ITEM_ID
      FROM ITEM_INFO I
      RIGHT JOIN ITEM_TREE T
      ON I.ITEM_ID = T.PARENT_ITEM_ID
      WHERE RARITY = 'RARE') X
JOIN ITEM_INFO I ON X.ITEM_ID = I.ITEM_ID
ORDER BY ITEM_ID DESC

 

서브쿼리는 X로 이름을 지정해 주었습니다. X의 아이템 아이디와 ITEM_INFO 테이블(I)의 아이템 아이디가 같다면 아이디/이름/레어리티를 셀렉하여 프린트하고, 아이템 아이디를 기준으로 내림차순 하여 정렬하도록 지정했습니다.

 

채점 결과 100.0

 

코드 통과, 정답입니다 :)

 

이해가 안 되는 부분이 있으시다면 댓글 달아주세요!

 

서브쿼리와 RIGHT JOIN 연습을 할 수 있었던 좋은 문제였습니다.

 

 

 

 

 

프로그래머스의 MySQL 코딩테스트 연습문제 '노선별 평균 역 사이 거리 조회하기' 를 풀었습니다. 서브쿼리와 ORDER BY에 대해 정리해두기 좋은 문제인 것 같아 블로그 포스팅을 해 보도록 하겠습니다.

 

https://school.programmers.co.kr/learn/courses/30/lessons/284531

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

먼저, 1차로 제출한 정답코드입니다. (오답)

SELECT ROUTE, 
        CONCAT(ROUND(SUM(D_BETWEEN_DIST), 1), "km") AS TOTAL_DISTANCE,
        CONCAT(ROUND(AVG(D_BETWEEN_DIST), 2), "km") AS AVERAGE_DISTANCE
FROM SUBWAY_DISTANCE
GROUP BY ROUTE
ORDER BY TOTAL_DISTANCE DESC

 

테스트 케이스는 통과했으나 정답으로 제출하면 결과가 틀리다고 나와 저를 당황스럽게 하였습니다. 무엇이 문제였을까요? 문제 조건을 다시 한 번 살펴보겠습니다.

1) 총 누계 거리와 평균 역 사이 거리의 컬럼명은 각각 TOTAL_DISTANCE, AVERAGE_DISTANCE 
2) 총 누계거리는 소수 둘째자리에서, 평균 역 사이 거리는 소수 셋째 자리에서 반올림 한 뒤 단위(km)를 함께 출력
3) 결과는 총 누계 거리를 기준으로 내림차순 정렬

 

왠지 CONCAT으로 스트링으로 만들어버린 값을 정렬하면서 3번에서 문제가 생기지 않을까 싶었어요. 그래서 1차로 제출했던 코드에서 CONCAT 함수를 제외한 전체를 서브쿼리로 사용해 보기로 했습니다. 

 

(SELECT ROUTE, 
        ROUND(SUM(D_BETWEEN_DIST), 1) AS TOTAL_DISTANCE,
        ROUND(AVG(D_BETWEEN_DIST), 2) AS AVERAGE_DISTANCE
FROM SUBWAY_DISTANCE
GROUP BY ROUTE
ORDER BY TOTAL_DISTANCE DESC) BF

 

먼저 CONCAT을 빼버린 부분을 전체 ( ) 괄호로 묶어서 임시 테이블 BF로 만들어 자기참조합니다.

그럼 2차로 제출한 정답코드를 보여드리겠습니다.

SELECT BF.ROUTE,
       CONCAT(BF.TOTAL_DISTANCE, "km") AS TOTAL_DISTANCE,
       CONCAT(BF.AVERAGE_DISTANCE, "km") AS AVERAGE_DISTANCE
       
FROM (SELECT ROUTE, 
        ROUND(SUM(D_BETWEEN_DIST), 1) AS TOTAL_DISTANCE,
        ROUND(AVG(D_BETWEEN_DIST), 2) AS AVERAGE_DISTANCE
FROM SUBWAY_DISTANCE
GROUP BY ROUTE
ORDER BY TOTAL_DISTANCE DESC) BF

 

합계: 100.0 / 100.0 (정답)

 

FROM 뒤에 임시 테이블(이너 테이블) BF를 넣어 줍니다. TOTAL_DISTANCE를 기준으로 내림차순 정렬은 이미 임시 테이블 BF에서 숫자형태로 완료가 된 상태입니다. 이렇게 정렬이 완료된 임시 테이블에서 CONCAT을 이용해 "km"을 붙이고 스트링화 해주었더니 정답으로 인정이 되었습니다.

 

 

서브쿼리와 정렬에 대해 생각해볼 수 있는 좋은 문제였습니다.

 

 

+ Recent posts