프로그래머스 SQL 고득점 Kit
https://school.programmers.co.kr/learn/challenges?tab=sql_practice_kit
FOOD_PRODUCT와 FOOD_ORDER 테이블에서 생산일자가 2022년 5월인 식품들의 식품 ID, 식품 이름, 총매출을 조회하는 SQL문을 작성해주세요.
이때 결과는 총매출을 기준으로 내림차순 정렬해주시고 총매출이 같다면 식품 ID를 기준으로 오름차순 정렬해주세요.
SELECT D.ID, D.EMAIL, D.FIRST_NAME, D.LAST_NAME
FROM DEVELOPERS AS D
JOIN SKILLCODES AS S
ON (D.SKILL_CODE & S.code) <> 0
WHERE S.CATEGORY = 'Front End'
ORDER BY D.ID ASC;
확실히 LEVEL4의 위엄을 느낀 문제였다.
문제를 보게 되면
스킬의 코드는 2진수로 표현했을 때 각 bit로 구분될 수 있도록 2의 제곱수로 구성되어 있습니다. - SKILLCODES 테이블
SKILL_CODE가 400 (=b'110010000')이라면, 이는 SKILLCODES 테이블에서 CODE가 256 (=b'100000000'), 128 (=b'10000000'), 16 (=b'10000') 에 해당하는 스킬을 가졌다는 것을 의미 - DEVELOPERS 테이블
다음과 같은 설명이 있다. 비트 연산자를 활용해야하는 것도 익숙하지 않았고, 테이블간 조인할 PK, FK도 존재하지 않아서 접근에 있어서 어려움을 느꼈다.
따라서 익숙하지 않았던 비트 연산자에 대해 정리하였다.
연산자 | 이름 | 설명 | 예시 (10진수) | 예시 (2진수) | 결과 (10진수) |
---|---|---|---|---|---|
& | 비트 AND | 두 비트 모두 1이면 1, 아니면 0 | 6 & 3 | 110 & 011 | 2 (010) |
` | ` | 비트 OR | 두 비트 중 하나라도 1이면 1 | 6 \| 3 | 110 \| 011 |
^ | 비트 XOR | 두 비트가 다르면 1, 같으면 0 | 6 ^ 3 | 110 ^ 011 | 5 (101) |
~ | 비트 NOT | 0은 1로, 1은 0으로 (1의 보수) | ~6 | ~00000110 | 음수로 표현됨(부호 비트 포함) |
<< | 왼쪽 시프트 | 모든 비트를 왼쪽으로 이동, 오른쪽은 0 채움 | 3 << 1 | 011 << 1 | 6 (110) |
>> | 오른쪽 시프트 | 모든 비트를 오른쪽으로 이동, 왼쪽은 부호에 따라 채움 | 6 >> 1 | 110 >> 1 | 3 (011) |
① 특정 비트가 켜져 있는지 확인
-- flags가 4번 비트를 가지고 있는지?
WHERE (flags & 4) <> 0
② 여러 비트 중 하나라도 포함되는지 확인
-- flags가 1번(001) 또는 4번(100) 비트를 가지고 있는지?
WHERE (flags & (1 | 4)) <> 0
③ 여러 비트를 모두 가지고 있는지 확인
-- flags가 1번(001)과 4번(100) 비트를 모두 가지고 있는지?
WHERE (flags & (1 | 4)) = (1 | 4)
④ 비트 합치기
SELECT BIT_OR(code) -- 여러 행의 code를 하나로 합친 비트마스크
FROM skillcodes
WHERE category = 'Front End';
MySQL에서 BIN(n) → 10진수를 2진 문자열로 변환
CONV(n, from_base, to_base) → 진법 변환
SELECT CONV('110010000', 2, 10); -- 2진 문자열 → 10진수
SELECT BIN(400); -- 10진수 → 2진 문자열
공간 절약: 여러 boolean 상태를 하나의 정수 컬럼에 저장 가능
검색 속도: 인덱스와 결합하면 매우 빠르게 필터링 가능
조합 연산: AND, OR로 손쉽게 조건 결합 가능