취업준비/코딩테스트 문제 풀이

[프로그래머스 SQL 코딩테스트 연습] Lv3. 업그레이드 할 수 없는 아이템 구하기 (MySQL)

상급닌자연습생 2024. 6. 19. 13:25

🤔 문제

어느 한 게임에서 사용되는 아이템들은 업그레이드가 가능합니다.

'ITEM_A' → 'ITEM_B'와 같이 업그레이드가 가능할 때 'ITEM_A'를 'ITEM_B'의 PARENT 아이템, PARENT 아이템이 없는 아이템을 ROOT 아이템이라고 합니다.

 

예를 들어 'ITEM_A' → 'ITEM_B' → 'ITEM_C' 와 같이 업그레이드가 가능한 아이템이 있다면

'ITEM_C'의 PARENT 아이템은 'ITEM_B'

'ITEM_B'의 PARENT 아이템은 'ITEM_A'

ROOT 아이템은 'ITEM_A'가 됩니다.

 

다음은 해당 게임에서 사용되는 아이템 정보를 담은 `ITEM_INFO` 테이블과 아이템 관계를 나타낸 `ITEM_TREE` 테이블입니다.

`ITEM_INFO` 테이블은 다음과 같으며, `ITEM_ID`, `ITEM_NAME`, `RARITY`, `PRICE`는 각각 아이템 ID, 아이템 명, 아이템의 희귀도, 아이템의 가격을 나타냅니다.

 

`ITEM_TREE` 테이블은 다음과 같으며, `ITEM_ID`, `PARENT_ITEM_ID`는 각각 아이템 ID, PARENT 아이템의 ID를 나타냅니다.

 

단, 각 아이템들은 오직 하나의 PARENT 아이템 ID 를 가지며, ROOT 아이템의 PARENT 아이템 ID 는 NULL 입니다.

ROOT 아이템이 없는 경우는 존재하지 않습니다.

더 이상 업그레이드할 수 없는 아이템의 아이템 ID(ITEM_ID), 아이템 명(ITEM_NAME), 아이템의 희귀도(RARITY)를 출력하는 SQL 문을 작성해 주세요. 이때 결과는 아이템 ID를 기준으로 내림차순 정렬해 주세요.

 

 

 

예시

예를 들어 `ITEM_INFO` 테이블이 다음과 같고

 

`ITEM_TREE` 테이블이 다음과 같다면

 

'ITEM_A' 는 'ITEM_B', 'ITEM_C' 로 업그레이드가 가능하며 'ITEM_B' 는 'ITEM_D', 'ITEM_E' 로 업그레이드가 가능합니다. 'ITEM_C', 'ITEM_D', 'ITEM_E' 는 더 이상 업그레이드가 가능하지 않으므로 결과는 다음과 같이 나와야 합니다.

 

 

 

 

 

 

 


💻 나의 풀이

첫 번째 시도(오답)

WITH PARENT AS(
    SELECT ITEM_ID AS PARENTS
    FROM ITEM_TREE
    WHERE ITEM_ID IN PARENT_ITEM_ID -- (1) 해당 아이템이 부모 아이템이거나
    AND ITEM_ID IN (SELECT ITEM_ID -- (2) 전체에서 루트 아이템밖에 없는 경우
                   FROM ITEM_TREE
                   WHERE COUNT(ITEM_ID) = 1
                   AND PARENT_ITEM_ID IS NULL)
)
SELECT ITEM_ID, ITEM_NAME, RARITY
FROM ITEM_INFO i
JOIN PARENT p ON i.ITEM_ID = p.PARENTS
WHERE p.PARENTS IS NULL
ORDER BY 1 DESC;

 

우선 문제에서 말하는 [더 이상 업그레이드할 수 없는 아이템]은 말단 노드들을 뜻한다.

이를 구하게 위해서,

(1) 해당 `ITEM_ID`가 `PARENT_ITEM_ID`이거나 (2) 전체에서 루트 아이템밖에 없는 경우를 제외한 ITEM들이 말단 노드라고 생각했다. ((1)은 그렇다치고 (2)는 왜 그렇게 생각했지..)

 

그래서 먼제 CTE절로 (1)과 (2)를 만족하는 `ITEM_ID`를 뽑고 `ITEM_INFO`와 조인해서 `ITEM_ID`가 NULL인 것들만 조회하려고 했다.

당연하게도 오답이다.

 

 

 

두번째 시도(오답)

SELECT ITEM_ID, ITEM_NAME, RARITY
FROM ITEM_INFO
WHERE ITEM_ID NOT IN (SELECT PARENT_ITEM_ID 
                      FROM ITEM_TREE)
ORDER BY 1 DESC;

 

위의 생각을 반전시켜보니, 그냥 `PARENT_ITEM_ID`에 없는 `ITEM_ID`를 조회하면 되는 것이었다.

그런데 오답으로 나왔다..

 

 

 

 

 


🖍 오답노트

틀린 이유

두번째 시도가 틀린 이유가 무엇일까?

 

`NOT IN`을 사용하게 되면 서브쿼리에 있는 모든 `PARENT_ITEM_ID`에 대해서 `!=`의 결과가 참인 데이터가 조회된다.

`PARENT_ITEM_ID`컬럼에는 NULL값(최상단 노드)이 있기 때문에 `NULL`과 `!=`연산을 하게 될 경우, UNKNOWN(거짓)값이 리턴되어 전부 조회되지 않는 것이다. 따라서 `PARENT_ITEM_ID`컬럼이 `NULL`인 행은 제외하고 조회해야 한다.

 

 

 

 

정답 풀이

SELECT ITEM_ID, ITEM_NAME, RARITY
FROM ITEM_INFO
WHERE ITEM_ID NOT IN (SELECT PARENT_ITEM_ID 
                      FROM ITEM_TREE
                     WHERE PARENT_ITEM_ID IS NOT NULL)
ORDER BY 1 DESC;

 

 

 

 

 

 

 


✅ 핵심 정리

1. IN

 

 

 

2. NOT IN

 

 

 

3. EXISTS

 

 

 

 

4. NOT EXISTS

 

 

 

 

 


🔗 References

[틀린 이유 참고]

https://velog.io/@jerry_bak/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-SQL-%EC%97%85%EA%B7%B8%EB%A0%88%EC%9D%B4%EB%93%9C-%ED%95%A0-%EC%88%98-%EC%97%86%EB%8A%94-%EC%95%84%EC%9D%B4%ED%85%9C-%EA%B5%AC%ED%95%98%EA%B8%B0

 

[프로그래머스 SQL] 업그레이드 할 수 없는 아이템 구하기

https://school.programmers.co.kr/learn/courses/30/lessons/273712더이상 업그레이드 할 수 없는 아이템 조회하기처음엔 이렇게 작성했었다. parent_item_id에 있지 않는 데이터는 더이상 업그레이드를 할 수

velog.io

 

 

[NOT IN vs. NOT EXISTS 참고]

https://wildeveloperetrain.tistory.com/223

 

(MySQL) IN, NOT IN, EXISTS, NOT EXISTS 동작 방식 정리

해당 내용은 IN / NOT IN / EXISTS / NOT EXISTS 동작 방식을 정리한 내용으로 MySQL을 기준으로 실행하고 작성된 내용이지만 MSSQL, Oracle 등에서도 적용되는 내용입니다. (예시에 사용될 orders table, customers ta

wildeveloperetrain.tistory.com