Skip to main content

[SQL] 276036 언어별 개발자 분류하기

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

image.png

image.png

image.png

1. 문제

  • ​테이블: DEVELOPERS, SKILLCODES
  • 조건:
    • A → Front End 스킬 + Python 스킬을 모두 가진 개발자
    • B → C# 스킬을 가진 개발자
    • C → 그 외 Front End 스킬을 가진 개발자
  • 출력 컬럼 : GRADE, ID, EMAIL
  • 정렬 기준 : GRADE, ID 오름차순
  • 주의 : GRADE가 부여되는 개발자만 조회

2. 오답정리

-- 코드를 작성해주세요
SELECT CASE 
            WHEN s.CODE & d.SKILL_CODE = 256 
                 AND CATEGORY = 'Front End' THEN 'A'
            WHEN s.CODE & d.SKILL_CODE = 1024 THEN 'B'
            WHEN CATEGORY = 'Front End' THEN 'C' 
       END AS GRADE,
       d.ID,
       d.EMAIL
FROM SKILLCODES s 
JOIN DEVELOPERS d 
     ON (s.CODE & d.SKILL_CODE) > 0
ORDER BY GRADE, d.ID;

image.png

​1. 동시에 두 스킬 보유(A) 조건 충족 안됨

WHEN s.CODE & d.SKILL_CODE = 256 AND CATEGORY = 'Front End' THEN 'A'

내가 쓴 CASE문은 단일행 기준이다. 특정 코드 값 256과 "Front End"만 체크하고 있다.
하지만 실제 문제는 Front End와 Python이 동시에 존재하는지 확인해야 한다.

단일행 s.CODE & d.SKILL_CODE 만으로는 두 스킬을 동시에 보유하고 있는지 판별을 할 수 없다.
이건 SUM(CODE)나 BIT_OR(CODE) 같은 집계를 써서 개발자 한 명에 따라 가진 전체 스킬을 한 번에 보고 조건을 만들어야 한다.


2. 조인만 하고 개발자 스킬을 하나로 합치지 않음

ON (s.CODE & d.SKILL_CODE) > 0

이건 '개발자가 해당 스킬을 가지고 있으면 매칭'이다. 이렇게 하면 한 개발자가 여러 스킬을 가질 경우 d.ID가 여러 번 중복해서 나오고, CASE문도 스킬별로 따로 적용해야 돼서 GRADE판정이 꼬인다.

조인 후 그대로 쓰지 말고 GROUP BY d.ID를 해서 개발자 단위로 스킬을 합쳐야 한다.


3. 스킬 구분을 코드값에 의존함

나는 Python = 256, C# = 1024 로 숫자 값을 직접 썼는데 스킬 이름 컬럼이 있기 때문에 NAME으로 판별해야 한다.'

  • Python → NAME = 'Python'
  • C# = NAME = 'C#'
  • Front End → CATEGORY = 'Front End'

3. 정답쿼리

이중 CASE문

-- 코드를 작성해주세요
SELECT CASE 
            WHEN SUM(CASE WHEN s.CATEGORY = 'Front End' THEN 1 ELSE 0 END) > 0
                 AND SUM(CASE WHEN s.NAME = 'PYTHON' THEN 1 ELSE 0 END) > 0
                 THEN 'A'
            WHEN SUM(CASE WHEN s.NAME = 'C#' THEN 1 ELSE 0 END) > 0
                 THEN 'B'
            WHEN SUM(CASE WHEN s.CATEGORY = 'Front End' THEN 1 ELSE 0 END) > 0
                 THEN 'C'    
       END AS GRADE,
       d.ID,
       d.EMAIL
FROM SKILLCODES s 
JOIN DEVELOPERS d 
     ON (s.CODE & d.SKILL_CODE) > 0
GROUP BY d.ID, d.EMAIL
HAVING GRADE IS NOT NULL
ORDER BY GRADE, d.ID;

1. JOIN

  • d.SKILL_CODE & s.CODE > 0 → 개발자가 해당 스킬을 가지고 있으면 매칭

2. CASE + SUM

  • SUM(CASE WHEN ... THEN 1 END) 방식으로 개발자가 가진 스킬 중 Python, C#, Front End 보유 여부 체크
    • Python과 Front End 모두 있으면 A
    • C# 있으면 B
    • Front End만 있으면 C

3. GROUP BY

  • 개발자(d.ID, d.EMAIL) 단위로 스킬 합쳐서 판별

4. HAVING GRADE IS NOT NULL

  • GRADE가 매겨진 개발자만 출력

5. 정렬

  • ORDER BY GRADE, d.ID

비트연산 버전 SQL 쿼리

이건 궁금해서 찾아본 비트 연산만으로 푸는 방법이다.
DEVELOPERS.SKILL_CODE 는 여러 스킬의 CODE를 합친 값(비트 OR)이라, 특정 스킬을 가졌는지 확인하려면 & 연산으로 체크한다.

이렇게 하면 JOIN 없이 DEVELOPERS 테이블만으로도 문제 조건을 처리할 수 있다.

SELECT CASE
           WHEN (d.SKILL_CODE & (SELECT CODE FROM SKILLCODES WHERE NAME = 'Python')) > 0
                AND (d.SKILL_CODE & (SELECT CODE FROM SKILLCODES WHERE CATEGORY = 'Front End')) > 0
                THEN 'A'
           WHEN (d.SKILL_CODE & (SELECT CODE FROM SKILLCODES WHERE NAME = 'C#')) > 0
                THEN 'B'
           WHEN (d.SKILL_CODE & (SELECT CODE FROM SKILLCODES WHERE CATEGORY = 'Front End')) > 0
                THEN 'C'
       END AS GRADE,
       d.ID,
       d.EMAIL
FROM DEVELOPERS d
WHERE (d.SKILL_CODE & (SELECT CODE FROM SKILLCODES WHERE NAME = 'Python')) > 0
   OR (d.SKILL_CODE & (SELECT CODE FROM SKILLCODES WHERE CATEGORY = 'Front End')) > 0
   OR (d.SKILL_CODE & (SELECT CODE FROM SKILLCODES WHERE NAME = 'C#')) > 0
ORDER BY GRADE, d.ID;