데이터베이스를 다루다 보면 쿼리 안에서 if/then 형태의 조건 처리가 필요한 경우가 자주 있습니다. 예를 들어 직원 목록을 살펴보며 근속 기간이 1년을 넘은 직원의 수습 상태를 변경하거나, 리더보드의 플레이어 중 상위 3위 안에 든 사람에게 '우승자' 표시를 붙이는 경우를 생각해 볼 수 있습니다.
SQL에서 이런 조건 처리를 하려면 CASE 문을 사용해야 합니다. SQL CASE 문은 엑셀(Microsoft Excel)에서 if/then 절차를 실행하는 것과 비슷한 방식으로, 쿼리 안에서 조건 분기 로직을 구현할 수 있게 해줍니다.
이 글에서는 SQL CASE 문의 기본 개념과 쿼리 활용법을 살펴보고, 여러 조건을 결합하는 방법과 집계 함수(aggregate function)와 함께 사용하는 방법까지 알아보겠습니다.
쿼리 기본 복습
데이터베이스에서 정보를 조회하려면 쿼리(query)를 작성해야 합니다. 쿼리는 거의 항상 SELECT 문으로 시작하며, SELECT는 어떤 열(column)을 반환할지 데이터베이스에 지시하는 역할을 합니다. 또한 대부분의 쿼리에는 FROM 절이 포함되어 어느 테이블을 대상으로 작업할지 지정합니다.
SQL 쿼리의 기본 문법은 다음과 같습니다:
SELECT column_name FROM table_name WHERE conditions_are_met;
예시를 통해 확인해 보겠습니다. 아래 쿼리는 employees 테이블에 있는 모든 직원의 이름을 반환합니다:
SELECT name FROM employees;
실행 결과는 다음과 같습니다:
| name |
| Luke Mike Hannah Geoff Alexis Emma Jonah Adam |
(8 rows)
여러 열을 조회하고 싶다면 열 이름을 쉼표로 구분해 나열하면 됩니다. 모든 열의 데이터를 가져오고 싶다면 테이블의 전체 열을 의미하는 별표(*) 연산자를 사용할 수 있습니다.
특정 조건에 맞는 레코드만 필터링하고 싶다면 WHERE 절을 사용합니다. 예를 들어 Albany 지점에 소속된 모든 직원의 이름을 찾는 쿼리는 다음과 같습니다:
SELECT name FROM employees WHERE branch = 'Albany';
실행 결과:
| name |
| Emma Jonah |
(2 rows)
여기까지의 쿼리는 비교적 단순합니다. 그렇다면 쿼리를 실행하면서 if/then 연산을 수행하려면 어떻게 해야 할까요? 바로 이럴 때 SQL CASE 문이 유용합니다.
SQL CASE 문이란?
CASE 문은 SQL 코드에서 if/then 로직을 정의할 때 사용합니다. 예를 들어 근속 연수가 5년 이상인 모든 직원에게 급여를 인상해 주고 싶다면 CASE 문을 활용할 수 있습니다.
SQL CASE 문의 기본 문법은 다음과 같습니다:
SELECT column1_name, CASE WHEN column2_name = 'X' THEN 'Y' ELSE NULL END AS column3_name FROM table_name;
이 쿼리는 다소 복잡해 보이니 예제를 통해 동작 방식을 살펴보겠습니다. '이달의 직원(employee of the month)' 상을 5회 초과 받은 직원에게 200달러의 인상을 적용하고 싶다고 가정해 봅시다. 이 목표를 달성할 수 있는 SQL 문은 다음과 같습니다:
SELECT name, CASE WHEN employee_month_awards > 5 THEN 200 ELSE NULL END AS pending_raise FROM employees;
검색형 CASE 표현식(searched case expression)의 실행 결과는 다음과 같습니다:
| name | pending_raise |
| Luke | |
| Mike | |
| Hannah | |
| Geoff | |
| Alexis | |
| Emma | 200 |
| Jonah | |
| Adam | 200 |
(8 rows)
동작 방식을 하나씩 살펴보겠습니다. CASE 문은 각 레코드를 검사하며 조건식 employee_month_awards > 5가 참인지 평가합니다. 조건식이 참이면 pending_raise 열에 값 200이 출력되고, 거짓이면 null 값이 그대로 남습니다.
최종적으로 쿼리는 직원 이름 목록과 각 직원의 예정된 인상액(pending raise)을 반환합니다.
주목할 점은 SQL CASE 문이 실제 테이블에 새로운 열을 추가하지 않는다는 것입니다. 대신 SELECT 쿼리의 출력 결과에 임시 열을 만들어 누가 인상 대상인지 확인할 수 있게 해줍니다.
또한 인상 대상이 아닌 직원에게도 특정 값을 표시하고 싶다면 ELSE 절에서 NULL 대신 원하는 값을 지정하면 됩니다. 데이터를 특정 순서로 보고 싶다면 ORDER BY 절을 추가해 결과를 정렬할 수도 있습니다.
SQL CASE와 다중 조건
CASE 문은 하나의 쿼리에서 여러 번 사용할 수 있습니다. 예를 들어 상을 3개 이상 받은 직원에게는 50달러를, 5개를 초과해 받은 직원에게는 200달러를 인상해 주고 싶다면 다음과 같이 작성할 수 있습니다:
SELECT name, CASE WHEN employee_month_awards > 5 THEN 200 WHEN employee_month_awards > 3 THEN 50 ELSE 0 END AS pending_raise FROM employees;
쿼리 출력 결과는 다음과 같습니다:
| name | pending_raise |
| Luke | 50 |
| Mike | 0 |
| Hannah | 0 |
| Geoff | 0 |
| Alexis | 0 |
| Emma | 200 |
| Jonah | 50 |
| Adam | 200 |
(8 rows)
이 예제에서 CASE 문의 조건들은 작성된 순서대로 평가됩니다.
즉, 쿼리는 먼저 상을 5개 초과 받은 사람을 찾아 인상액을 200으로 설정합니다. 그다음 상을 3개 초과 받은 사람을 찾아 인상액을 50으로 설정합니다. 마지막으로 어떤 조건에도 해당하지 않는 직원의 인상액은 0으로 설정됩니다.
그런데 이 코드는 더 효율적으로 개선할 수 있습니다. 프로그램이 의도대로 동작하도록 문장의 순서에 의존하기보다는, 서로 겹치지 않는 조건을 작성하는 것이 좋습니다. 아래 쿼리는 위와 동일하게 동작하지만 AND 연산자를 사용해 직원이 받은 상의 개수를 명확하게 검사합니다:
SELECT name, CASE WHEN employee_month_awards >= 3 AND employee_month_awards <= 5 THEN 50 WHEN employee_month_awards > 5 THEN 200 ELSE 0 END AS pending_raise FROM employees;
이 쿼리는 앞선 쿼리와 동일한 결과를 반환합니다. 하지만 이 버전은 CASE 문의 순서에 의존하지 않기 때문에 조건을 잘못 배치해 발생하는 실수 가능성이 줄어듭니다.
SQL CASE와 집계 함수
CASE는 집계 함수와 함께 사용할 수도 있습니다. 특정 조건을 충족하는 행만 세고 싶을 때 특히 유용합니다. 예를 들어 200달러 보너스를 받을 자격이 있는 직원이 몇 명인지 알고 싶다면 CASE를 집계 함수와 함께 사용하면 됩니다.
CASE를 집계 함수와 함께 사용하는 문법은 다음과 같습니다:
SELECT column1_name, CASE WHEN column2_name = 'X' THEN 'Y' ELSE NULL END AS column3_name, COUNT(1) AS count FROM table_name GROUP BY column3_name;
예제를 통해 살펴보겠습니다. 50달러 이상의 보너스를 받을 자격이 있는 직원이 몇 명인지 알고 싶다고 가정해 봅시다. 다음 쿼리로 이 정보를 얻을 수 있습니다:
SELECT CASE WHEN employee_month_awards >= 3 AND employee_month_awards <= 5 THEN 50 WHEN employee_month_awards > 5 THEN 200 ELSE 0 END AS pending_raise, COUNT(1) AS count FROM employees GROUP BY pending_raise;
쿼리 실행 결과는 다음과 같습니다:
| pending_raise | count |
| 50 | 3 |
| 0 | 3 |
| 200 | 2 |
결과에서 볼 수 있듯이, 쿼리는 직원들이 받을 예정인 인상액 목록과 각 유형별 인원수를 반환했습니다. 즉, 50달러 인상 대상이 3명, 인상 대상이 아닌 직원이 3명, 200달러 인상 대상이 2명입니다.
마무리
이번 튜토리얼에서는 SQL CASE 문의 기본 개념과 쿼리에서 if/then 로직을 구현하는 방법을 살펴봤습니다. 또한 여러 조건을 결합해 사용하는 방법과 집계 함수와 함께 활용하는 방법도 알아봤습니다.
복습 차원에서, 올바른 CASE 표현식은 다음 규칙을 따라야 합니다:
CASE문은SELECT절 안에 위치해야 합니다.CASE문에는WHEN,THEN,END요소가 반드시 포함되어야 합니다.- 여러 개의
WHEN문과ELSE절은 선택적으로 사용할 수 있습니다. AND,OR같은 조건 연산자는WHEN과THEN절 사이에서 사용할 수 있습니다.
이제 여러분도 SQL 전문가처럼 CASE 문을 활용할 준비가 되었습니다!