MariaDB 강좌 / CASE로 조건별 값과 집계 만들기
CASE는 조건에 따라 하나의 값을 선택하는 SQL 표현식입니다. 상품 상태를 표시하거나 집계 함수 안에서 특정 조건의 값만 선택할 수 있으며, 조건의 순서·ELSE·NULL 처리에 따라 결과가 달라집니다.
CASE 표현식과 절차 제어를 구분하기
이 글의 CASE는 SELECT의 결과값 하나를 만드는 표현식입니다. 여러 SQL 문을 실행하는 저장 프로그램의 CASE 문과 구분합니다. 재고가 0인지·10보다 적은지 같은 조건을 평가하고 처음 참인 조건의 결과를 선택하므로 겹치는 조건의 순서가 중요합니다. 조건식 자체가 맞아도 집계 단위를 잘못 정하면 결과가 달라집니다. COUNT·SUM·AVG·MIN·MAX로 집계하기의 COUNT·SUM 기준과 조회 종합 실습: 월별 매출·고객별 구매·미판매 상품의 보고서 검증을 함께 확인하세요.
| 형태 | 사용 상황 | 예 |
|---|---|---|
| CASE 값 WHEN 값 THEN 결과 | 동등한 코드 매핑 | 분류 '문구'를 표시 이름으로 |
| CASE WHEN 조건 THEN 결과 | 범위·복합 조건 | stock < 10 |
| ELSE 결과 | 어느 조건에도 해당하지 않음 | 판매 가능 |
| END | 표현식 끝 | 뒤에 AS 별칭 지정 |
재고가 서로 다른 상품으로 준비하기
학습용 MariaDB 서버의 shopcourse에 course_user로 접속합니다. 명령줄 클라이언트와 UTF-8 SQL 파일 실행 방법대로 코드를 UTF-8 파일에 저장하고 SOURCE C:/mariadb-lab/lesson.sql;처럼 실제 파일 경로로 실행할 수 있습니다. SQL 문은 운영체제 터미널이 아닌 MariaDB 연결 안에서 실행합니다.
먼저 SELECT VERSION(), DATABASE();와 SHOW TABLES;로 대상 서버·DB·이름 중복을 확인합니다. 아래 products_24_lab는 이 글의 독립된 연습용 이름입니다. 이미 존재하면 정의와 행을 확인하고, 보관할 자료가 없는 이 글의 실습 테이블임이 확실할 때만 마지막 절의 정리 순서로 지운 뒤 다시 만듭니다. 기존 강좌의 동명 없는 테이블이나 운영 데이터는 삭제하지 않습니다.
USE shopcourse; CREATE TABLE products_24_lab ( product_id INT NOT NULL AUTO_INCREMENT, product_name VARCHAR(100) NOT NULL, category VARCHAR(30) NOT NULL, price DECIMAL(10,2) NOT NULL, stock INT NOT NULL DEFAULT 0, note VARCHAR(100) NULL DEFAULT NULL, PRIMARY KEY (product_id), CONSTRAINT ck_p24_price CHECK (price >= 0), CONSTRAINT ck_p24_stock CHECK (stock >= 0) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO products_24_lab (product_id,product_name,category,price,stock,note) VALUES (1, '노트', '문구', 3500.00, 20, NULL), (2, '볼펜', '문구', 1500.00, 0, ''), (3, '머그컵', '생활', 8000.00, 12, '선물 포장'), (4, '스탠드', '생활', 25000.00, 5, NULL), (5, '파일', '문구', 1500.00, 50, ''), (6, '케이블', '전자', 8000.00, 0, '호환 확인');
재고 0인 상품 두 개, 1~9개인 상품 한 개, 10개 이상인 상품 세 개입니다. 이 구분은 학습용 정책이므로 실제 판매 가능 상태에 예약·입고 예정·판매 중지 같은 다른 조건이 있다면 함께 설계해야 합니다.
좁은 조건부터 평가해 상태값 표시하기
SELECT product_id,product_name,stock,
CASE WHEN stock=0 THEN '품절'
WHEN stock<10 THEN '재고 적음'
ELSE '판매 가능' END AS stock_label
FROM products_24_lab ORDER BY product_id;
번호 2·6번은 품절, 4번은 재고 적음, 1·3·5번은 판매 가능입니다. stock < 10을 먼저 적으면 0도 그 조건에 해당하므로 품절 조건이 선택되지 않습니다. 조건 하나의 순서를 바꿔 결과를 비교한 다음 원래 순서로 되돌려 보세요.
ELSE를 생략했는데 어느 WHEN에도 해당하지 않으면 결과가 NULL입니다. 화면에서 비어 보이는 이유가 원본 NULL인지 CASE의 미정의 분기인지 구분해야 합니다. CASE 연산자의 선택 순서와 ELSE를 확인할 수 있습니다.
SUM과 COUNT 안에서 조건별 개수 구하기
SELECT SUM(CASE WHEN stock=0 THEN 1 ELSE 0 END) AS out_of_stock, COUNT(CASE WHEN stock=0 THEN 1 END) AS also_out_of_stock, COUNT(CASE WHEN stock=0 THEN 1 ELSE 0 END) AS all_non_null, SUM(CASE WHEN category='문구' THEN price*stock ELSE 0 END) AS stationery_value FROM products_24_lab;
| 표현 | 결과 | 이유 |
|---|---|---|
| SUM(CASE ... THEN 1 ELSE 0 END) | 2 | 품절 행에 1을 더함 |
| COUNT(CASE ... THEN 1 END) | 2 | 품절 이외에는 NULL이라 제외 |
| COUNT(CASE ... THEN 1 ELSE 0 END) | 6 | 0도 NULL이 아닌 값이라 포함 |
| 문구 재고 금액 | 145000.00 | 문구 행의 가격×재고만 합산 |
COUNT가 숫자 1만 센다고 오해하면 ELSE 0을 넣은 결과를 잘못 해석합니다. COUNT(표현식)는 NULL이 아닌 표현식 값을 세며 0도 포함합니다. 조건별 집계에서는 SUM의 1·0 방식 또는 COUNT의 1·NULL 방식을 의도에 맞게 선택합니다.
결과 타입과 NULL 정책을 함께 정하기
THEN에는 숫자, ELSE에는 임의의 문자열을 섞으면 결과 타입 변환 때문에 후속 계산이나 정렬을 이해하기 어려워질 수 있습니다. 계산용 금액은 숫자로 유지하고 상태 문구는 별도 열로 반환하는 편이 명확합니다. 가격이 NULL일 때 0원으로 처리할지도 업무에서 결정해야 합니다.
SELECT category, SUM(CASE WHEN stock>0 THEN 1 ELSE 0 END) AS available_products FROM products_24_lab GROUP BY category ORDER BY category;
분류별 재고 보유 상품 수는 문구 2개·생활 2개·전자 0개입니다. WHERE stock>0을 먼저 적용하면 전자 그룹 자체가 사라지지만 CASE로 합산하면 전자 그룹에 0을 표시할 수 있습니다. 어떤 결과 형태가 필요한지에 따라 두 방식을 선택합니다.
집계 전 원본 행과 분기를 확인하기
합계만 한 번에 확인하지 말고 먼저 기본키·재고·CASE 결과를 출력해 각 행이 어느 분기로 갔는지 살펴봅니다. 조건에 =와 >를 혼동했는지, AND·OR 괄호가 맞는지, ELSE를 빠뜨리지 않았는지도 확인합니다. CASE는 조회 결과를 만들며 원본 stock을 수정하지 않습니다.
반복하기 전 현재 DB와 실제 정의·행을 확인하고 필요한 자료를 백업합니다. 보관할 데이터가 없는 이 글의 전용 실습 객체만 아래 순서로 정리합니다. 외래키가 있으면 자식부터 지웁니다. DROP TABLE은 구조와 데이터를 모두 없애며 일반적인 ROLLBACK으로 복원되지 않으므로 취소 가능한 DML 실습과 분리합니다.
DROP TABLE shopcourse.products_24_lab;










