관리 메뉴

한다 공부

[MySQL] SQL 문제풀이 (8문제) 본문

CS/SQL

[MySQL] SQL 문제풀이 (8문제)

사과당근 2024. 2. 29. 00:01

SQL 고득점 Kit의 문제를 다 푼지 어언 2개월..

8문제가 새로 추가되었다.. (2024/02/25 기준)

이 8문제를 풀어보고자 합니다.

 

1, 4, 6, 7번은 아이템과 관련된 문제 시리즈이고,

2, 3, 5, 8번은 개발자 찾기 관련된 문제 시리즈입니다.

 

SELECT

1. 업그레이드 된 아이템 구하기

테이블을 삼중 조인하여 parent 아이템의 데이터를 select 했다

이때, 첫번째 join 시 left join을 하지 않았다.

왜냐하면 parent 아이템이 없는 경우도 있기 때문이다.

(left join을 할 경우, parent 아이템이 null로 출력되므로)

SELECT P.ITEM_ID, P.ITEM_NAME, P.RARITY
FROM ITEM_INFO AS I JOIN ITEM_TREE AS T
ON I.ITEM_ID = T.PARENT_ITEM_ID
LEFT JOIN ITEM_INFO AS P
ON T.ITEM_ID = P.ITEM_ID
WHERE I.RARITY = 'RARE'
ORDER BY P.ITEM_ID DESC;

 

2. Python 개발자 찾기

SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPER_INFOS
WHERE SKILL_1 = 'Python' OR SKILL_2 = 'Python' OR SKILL_3 = 'Python'
ORDER BY ID;

 

3. 조건에 맞는 개발자 찾기

여태까지 AND, OR을 사용한 논리 연산자는 많이 사용했는데,

&, | 와 같은 비트 논리 연산자는 사용해 본 적이 없어서 이 문제가 신기했다.

&는 AND와 같지만, 비트끼리 비교한 것이며

|는 OR과 같지만, 마찬가지로 비트끼리 비교한 것이다.

 

예를 들어 Python 의 이진수 코드가 1000이고 C#의 코드가 0100일 경우,

1*** 이거나 *1**이라는 코드를 가지고 있는 사람은

Python이나 C# 스킬을 가진 사람 인 것이다.

그래서 두 코드를 더해서 1100을 만든 다음, 내가 가진 스킬코드와 비교하고자 한다.

 

두 스킬을 더한 1100 코드와, 내가 가진 스킬 코드에

비트 논리 연산자인 & 를 사용했을 경우,

0보다 크면 하나 이상의 스킬이 겹친다는 뜻이고,

조건에 맞는 개발자를 고를 수 있게 되는 것이다.

SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPERS
WHERE SKILL_CODE & (
    SELECT SUM(CODE)
    FROM SKILLCODES
    WHERE NAME = 'Python' OR NAME = 'C#') > 0
ORDER BY ID;

 

SUM, MIN, MAX

4. 조건에 맞는 아이템들의 가격의 총합 구하기

SELECT SUM(PRICE) AS TOTAL_PRICE
FROM ITEM_INFO
WHERE RARITY = "LEGEND";

 

GROUP BY

5. 언어별 개발자 구분하기

이 문제를 풀기 위해서는 with 절을 썼다.

이전에 recursive with 을 사용한 적이 있는데, with은 쉽게 말해 임시 테이블을 만드는 것이다.

python의 스킬코드를 저장한 py 테이블,

c#의 스킬코드를 저장한 cp 테이블,

프론트엔드 스킬코드를 모두 더한 값을 저장한 fe 테이블로 세개를 만들었다.

여러개의 임시 테이블을 만드려면 with을 한 번만 사용한 뒤 콤마(,) 로 구분하면 된다.

 

이후 if 문을 사용해 등급을 나누었다.

1. 현재의 스킬코드가 python 스킬코드를 포함하고, fe 스킬코드와 하나라도 일치하다면 A 등급

2. 현재의 스킬코드에 C#이 포함되어 있다면 B 등급

3. 아무 프론트엔드 스킬코드를 하나라도 가지고 있다면 C등급

 

마지막으로, GRADE가 NULL인 부분을 필터링 했는데

다른 문제에서도 봤다시피, WHERE 절에서 alias 사용이 안되므로 HANING 절을 사용했다.

WITH PY AS (
    SELECT CODE
    FROM SKILLCODES
    WHERE NAME = 'Python'
),
CP AS(
    SELECT CODE
    FROM SKILLCODES
    WHERE NAME = 'C#'
),
FE AS (
    SELECT SUM(CODE) AS CODE
    FROM SKILLCODES 
    WHERE CATEGORY = 'Front End'
)

SELECT IF(SKILL_CODE & PY.CODE AND SKILL_CODE & FE.CODE, 'A',
          IF(SKILL_CODE & CP.CODE, 'B',
            IF(SKILL_CODE & FE.CODE, 'C', NULL))) AS GRADE,
    ID, EMAIL
FROM DEVELOPERS, PY, CP, FE
HAVING GRADE IS NOT NULL
ORDER BY GRADE, ID;

 

IS NULL

6. ROOT 아이템 구하기

1번 문제와 유사한데 훨씬 쉽다.

두 테이블을 조인한 뒤, 부모 노드가 null인 데이터만 조회하면 된다.

SELECT I.ITEM_ID, I.ITEM_NAME
FROM ITEM_INFO AS I LEFT JOIN ITEM_TREE AS T
ON I.ITEM_ID = T.ITEM_ID
WHERE T.PARENT_ITEM_ID IS NULL
ORDER BY I.ITEM_ID;

 

7. 업그레이드 할 수 없는 아이템 구하기

PARENT_ITEM_ID에 해당하는 아이템은, ITEM_TREE의 ITEM_ID로 업그레이드 할 수 있다.

즉, PARENT_ITEM_ID에 해당하는 아이템은 모두 업그레이드 할 수 있으므로

이에 속하지 않는 (= NOT IN) 아이템이, 우리가 구하고자 하는 '업그레이드 할 수 없는 아이템' 이다.

그래서 NOT IN을 사용해서 다음과 같이 풀었다.

하지만, 서브쿼리를 보면 WHERE PARENT_ITEM_ID IS NOT NULL 이라는 절이 들어있는데.

이는 왜 들어있을까?

 

바로, NULL값은 비교시 Unknown (= FALSE) 을 반환하기 때문이다.

프로그래머스 예제를 보면, 서브쿼리의 결과 [null, 0, 0, 1, 1] 를 반환한다.

이를 ITEM_INFO의 ITEM_ID인 [0, 1, 2, 3, 4, 5]와 비교했을 때,

서브쿼리의 결과 중 하나인 null과도 비교하게 되므로 전부 false 처리가 되고,

실행 결과에 아무것도 남지 않게 되는 것이다.

 

따라서 서브쿼리에 WHERE PARENT_ITEM_ID IS NOT 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 ITEM_ID DESC;

 

JOIN

8. FrontEnd 개발자 찾기

이 문제도 3번 문제와 같다.

다만 조건이, Python, C# 개발자를 찾는 것이 아니라,

카테고리가 Front End 인 개발자를 찾으면 된다.

SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPERS 
WHERE SKILL_CODE & (
    SELECT SUM(CODE)
    FROM SKILLCODES
    WHERE CATEGORY = 'Front End') > 0
ORDER BY ID;

'CS > SQL' 카테고리의 다른 글

[MySQL] SQL 문제풀이 (String, Date)  (1) 2023.12.23
[MySQL] SQL 문제풀이 (JOIN)  (2) 2023.11.07
[MySQL] SQL 문제풀이 (GROUP BY)  (1) 2023.10.27
[MySQL] SQL 문제풀이 (SELECT)  (0) 2023.10.25
[MySQL] SQL 문제풀이 (6문제)  (0) 2023.09.18