1. Problem
은행 계좌의 월 소득(income)을 기준으로 세 가지 카테고리('Low', 'Average', 'High')의 계좌 수를 집계해야 한다. 이 문제의 핵심 제약 사항은 특정 카테고리에 속한 계좌가 0개이더라도 결과 테이블에 반드시 해당 카테고리 이름과 '0'이 표시되어야 한다는 점이다.
2. Solution
일반적인 GROUP BY 방식의 한계를 극복하기 위해, 각 카테고리를 독립적인 쿼리로 생성한 후 UNION ALL로 결합하는 방식을 사용한다.
- 고정 행 생성: SELECT 'Category Name'을 통해 실제 데이터 존재 여부와 상관없이 결과창에 노출될 항목(Skeleton)을 먼저 정의한다.
- 독립적 필터링: 각 쿼리가 특정 범위만 담당하므로 데이터가 없는 구간은 COUNT(*)가 자연스럽게 0을 반환하게 된다.
3. Takeaway (리포트 완결성과 쿼리 설계)
분석가가 실무 리포트를 작성할 때 갖추어야 할 '방어적 쿼리' 작성 능력을 정립한다.
- GROUP BY의 한계 인식: 일반적인 CASE WHEN + GROUP BY 구조는 '존재하는 데이터'를 분류하는 데 최적화되어 있다. 따라서 데이터가 없는 카테고리는 그룹화 대상에서 아예 제외되어 리포트에서 누락되는 현상이 발생한다.
- 데이터의 '무(無)'에서 '유(有)'를 창조하는 기술: 비즈니스 보고서는 항목이 고정되어야 가독성이 높아진다. UNION ALL은 단순한 데이터 합치기를 넘어, 보고서의 레이아웃(틀)을 유지하기 위한 강력한 도구가 된다.
- 경계값의 정밀도: strictly less(<), inclusive(BETWEEN/<=, >=), strictly greater(>)와 같은 문제의 조건을 쿼리에 정확히 반영하는 것은 데이터 분석가의 가장 기본적인 신뢰도 측정 지표이다.
https://leetcode.com/problems/count-salary-categories/description/
Table: Accounts
+-------------+------+
| Column Name | Type |
+-------------+------+
| account_id | int |
| income | int |
+-------------+------+
account_id is the primary key (column with unique values) for this table.
Each row contains information about the monthly income for one bank account.
Write a solution to calculate the number of bank accounts for each salary category. The salary categories are:
"Low Salary": All the salaries strictly less than $20000.
"Average Salary": All the salaries in the inclusive range [$20000, $50000].
"High Salary": All the salaries strictly greater than $50000.
The result table must contain all three categories. If there are no accounts in a category, return 0.
Return the result table in any order.
The result format is in the following example.
Example 1:
Input:
Accounts table:
+------------+--------+
| account_id | income |
+------------+--------+
| 3 | 108939 |
| 2 | 12747 |
| 8 | 87709 |
| 6 | 91796 |
+------------+--------+
Output:
+----------------+----------------+
| category | accounts_count |
+----------------+----------------+
| Low Salary | 1 |
| Average Salary | 0 |
| High Salary | 3 |
+----------------+----------------+
Explanation:
Low Salary: Account 2.
Average Salary: No accounts.
High Salary: Accounts 3, 6, and 8.
[SQL/Medium] Calculate Salary Categories
1. 문제 풀이의 핵심: "데이터의 무(無)에서 유(有)를 창조하라"
보통의 CASE WHEN이나 GROUP BY만 사용하면, 해당 카테고리에 속하는 계좌가 0개일 경우 그 카테고리 자체가 결과창에서 사라집니다. 하지만 문제에서는 결과에 세 카테고리가 모두 포함되어야 한다고 명시했습니다.
2. 해결 전략: 개별 쿼리 결합 (UNION 방식)
각 카테고리를 독립적으로 계산한 뒤 수직으로 합치는 방식이 가장 확실합니다. 이렇게 하면 데이터가 없어도 COUNT 함수가 0을 반환하며 행을 유지해 줍니다.
✅ 정답 쿼리
-- 1. Low Salary 집계
SELECT 'Low Salary' AS category, COUNT(*) AS accounts_count
FROM Accounts
WHERE income < 20000
UNION ALL
-- 2. Average Salary 집계
SELECT 'Average Salary' AS category, COUNT(*) AS accounts_count
FROM Accounts
WHERE income BETWEEN 20000 AND 50000
UNION ALL
-- 3. High Salary 집계
SELECT 'High Salary' AS category, COUNT(*) AS accounts_count
FROM Accounts
WHERE income > 50000;
3. 왜 CASE WHEN + GROUP BY로는 부족할까요?
일반적인 집계 방식은 다음과 같습니다:
# ❌ 데이터가 없는 카테고리는 결과에서 누락됨
SELECT sub.category, count(sub.account_id) AS accounts_count
FROM (SELECT *, CASE
WHEN income < 20000 THEN 'Low Salary'
WHEN income >= 20000 AND income <= 50000 THEN 'Average Salary'
ELSE 'High Salary'
END AS category
FROM Accounts) sub
GROUP BY sub.category;
만약 테이블에 income < 20000인 행이 단 하나도 없다면, 위 쿼리는 'Low Salary'라는 이름표 자체를 만들지 못합니다. 반면 UNION ALL 방식은 **"일단 'Low Salary'라고 적힌 행을 하나 만들어 놓고, 거기 필터에 걸리는 게 몇 개인지 세어봐"**라고 명령하는 것이라 0이라도 출력이 가능한 것입니다.

🎯 기업 쿼리테스트 출제자의 의도
이 문제는 실무 리포트 작성 시의 **'리포트 양식 준수 능력'**을 평가합니다.
- 데이터 무결성(Reporting Completeness): 값이 0이더라도 항목은 존재해야 하는 '완결된 보고서'를 만들 수 있는가?
- 부등호 경계 조건 처리: strictly less (<), inclusive (<=, >=), strictly greater (>) 조건을 정확히 쿼리에 녹여낼 수 있는가?
- UNION의 전략적 활용: 단순 합치기가 아니라, 고정된 레이아웃을 유지하기 위한 도구로 UNION을 활용할 수 있는가?
🚩 마무리
"결과에 반드시 포함되어야 한다면 UNION이 정답이다."
집계할 데이터가 없을 때 행 자체가 사라지는 것은 SQL의 기본 동작.
이를 극복하려면 각 항목을 고정값으로 갖는 서브쿼리들을 결합하는 방식이 가장 직관적이고 오류가 없다.
'Data Science > SQL' 카테고리의 다른 글
| [SQL/오답] AVG(조건식) 승인율 계산과 NULL 처리 (LeetCode1934 Medium) (0) | 2026.02.16 |
|---|---|
| [뉴스] DB까지 자연어로 가능한 시대 <다큐브, 예일대 'AI모델 검증' 벤치마크 1위 달성…中 텐센트 제쳤다> (0) | 2026.02.16 |
| [SQL/오답] 복합 조건 필터링; CASE WHEN과 UNION ALL (LeetCode1873 Easy) (0) | 2026.02.16 |
| [SQL/오답] 와이드 포맷을 롱 포맷으로: UNION ALL으로 Unpivot (LeetCode1795 Easy) (0) | 2026.02.15 |
| [SQL/오답] 비즈니스 로직에 따른 집합 분리: UNION과 WHERE OR의 (LeetCode1789 Easy) (0) | 2026.02.15 |