본문 바로가기
Data Science/SQL

[SQL/오답] 비즈니스 로직에 따른 집합 분리: UNION과 WHERE OR의 (LeetCode1789 Easy)

by 에르모사 쩐뉴 2026. 2. 15.

 

1. Problem

모든 사원의 '주 부서(Primary Department)'를 보고해야 한다. 조건은 다음과 같다.

  1. 소속 부서가 여러 개인 사원: primary_flag = 'Y'인 부서를 선택한다.
  2. 소속 부서가 단 하나인 사원: 플래그가 'N'이더라도 해당 부서를 선택한다. 단순히 특정 값을 찾는 것을 넘어, 사원별 소속 부서 개수라는 **'상태'**에 따라 적용할 필터링 규칙이 달라지는 것이 이 문제의 핵심이다.

2. Solution

복잡한 단일 로직 대신, 두 가지 케이스를 각각 추출하여 합치는 UNION 전략과 서브쿼리를 이용한 필터링 전략으로 풀이할 수 있다.

[방법 A] 분할 정복: UNION을 이용한 집합 결합 논리적으로 가장 명확한 방법이다. 'Y' 플래그를 가진 집단과 소속 부서가 하나인 집단을 각각 구하여 합친다.

[방법 B] WHERE 절 서브쿼리를 이용한 효율적 조회 테이블 스캔을 최적화하기 위해 OR 조건과 서브쿼리를 조합한다.

3. Takeaway (집계 함수와 비집계 컬럼의 관계)

쿼리 설계 시 데이터의 왜곡을 방지하기 위해 반드시 지켜야 할 객관적 원칙을 정립한다.

  • GROUP BY와 정보 손실: 유진 님의 오답 사례처럼 GROUP BY 후 서브쿼리 외부에서 특정 컬럼(primary_flag)을 필터링하는 것은 매우 위험하다. 그룹화되는 순간 집계되지 않은 나머지 행의 정보는 손실되거나 임의의 값이 남기 때문이다.
  • 배타적 논리의 분리: "하나일 때는 무조건 선택, 여러 개일 때는 조건 선택"과 같은 로직은 SQL에서 CASE WHEN보다 UNION이나 OR 서브쿼리가 더 직관적이고 견고한 결과를 보장한다.
  • 데이터 무결성과 예외 처리: "부서가 하나일 때 플래그는 'N'이다"라는 비즈니스 규칙을 별도의 케이스로 분리해낸 점이 분석가로서의 꼼꼼함을 보여준다.

 

 

Primary Department for Each Employee - LeetCode

Can you solve this real interview question? Primary Department for Each Employee - Table: Employee +---------------+---------+ | Column Name | Type | +---------------+---------+ | employee_id | int | | department_id | int | | primary_flag | varchar | +----

leetcode.com

 

Table: Employee

+---------------+---------+
| Column Name   |  Type   |
+---------------+---------+
| employee_id   | int     |
| department_id | int     |
| primary_flag  | varchar |
+---------------+---------+
(employee_id, department_id) is the primary key (combination of columns with unique values) for this table.
employee_id is the id of the employee.
department_id is the id of the department to which the employee belongs.
primary_flag is an ENUM (category) of type ('Y', 'N'). If the flag is 'Y', the department is the primary department for the employee. If the flag is 'N', the department is not the primary.
 

Employees can belong to multiple departments. When the employee joins other departments, they need to decide which department is their primary department. Note that when an employee belongs to only one department, their primary column is 'N'.

Write a solution to report all the employees with their primary department. For employees who belong to one department, report their only department.

Return the result table in any order.

The result format is in the following example.

 

Example 1:

Input: 
Employee table:
+-------------+---------------+--------------+
| employee_id | department_id | primary_flag |
+-------------+---------------+--------------+
| 1           | 1             | N            |
| 2           | 1             | Y            |
| 2           | 2             | N            |
| 3           | 3             | N            |
| 4           | 2             | N            |
| 4           | 3             | Y            |
| 4           | 4             | N            |
+-------------+---------------+--------------+
Output: 
+-------------+---------------+
| employee_id | department_id |
+-------------+---------------+
| 1           | 1             |
| 2           | 1             |
| 3           | 3             |
| 4           | 3             |
+-------------+---------------+
Explanation: 
- The Primary department for employee 1 is 1.
- The Primary department for employee 2 is 1.
- The Primary department for employee 3 is 3.
- The Primary department for employee 4 is 3.

 

1. 정답 쿼리 

-- 1. 부서가 여러 개이며 'Y' 플래그를 가진 사원
SELECT employee_id, department_id
FROM Employee
WHERE primary_flag = 'Y'

UNION

-- 2. 부서가 딱 하나뿐인 사원
SELECT employee_id, department_id
FROM Employee
GROUP BY employee_id
HAVING COUNT(employee_id) = 1;

더 효율적인 풀이 (WHERE 절 서브쿼리)

UNION 대신 OR 조건과 서브쿼리를 사용하여 한 번에 조회할 수도 있습니다

SELECT employee_id, department_id
FROM Employee
WHERE primary_flag = 'Y' 
   OR employee_id IN (
       SELECT employee_id
       FROM Employee
       GROUP BY employee_id
       HAVING COUNT(*) = 1
   );

2. 나의 오답

SELECT e.employee_id, e.department_id
FROM (SELECT *
      FROM Employee
      GROUP BY employee_id 
      HAVING COUNT(*) > 1) e
WHERE e.primary_flag = 'Y'

UNION ALL

SELECT employee_id, department_id
FROM Employee
GROUP BY employee_id 
HAVING COUNT(*) = 1;

❌ 기존 쿼리의 잠재적 오류 (MySQL 기준)

  • 이유: GROUP BY employee_id를 하면 한 명의 사원당 하나의 행으로 압축됩니다. 이때 부서가 여러 개인 사원의 경우, 어떤 department_id나 primary_flag가 남을지 알 수 없습니다(임의의 값). 따라서 그 결과물에서 다시 primary_flag = 'Y'를 찾는 것은 위험합니다.

🎯 기업 쿼리테스트 출제자의 의도

이 문제는 **"데이터 집합의 배타적 논리(Exclusive Logic)"**를 처리할 수 있는지 봅니다.

  1. 조건부 필터링: 특정 상황(부서 1개)에서는 무시해야 할 플래그를, 다른 상황(부서 여러 개)에서는 핵심 필터로 사용할 수 있는가?
  2. 집합 연산의 활용: 복잡한 단일 쿼리보다 UNION을 통해 문제를 쪼개어 해결하는 분할 정복(Divide and Conquer) 능력을 확인합니다.
  3. 예외 케이스 처리: "부서가 하나일 때는 'N'이다"라는 특이 조건을 놓치지 않고 반영하는 꼼꼼함을 체크합니다.

🚩 블로그 오답노트: "GROUP BY와 SELECT *의 위험성"

"그룹화된 결과에서 개별 행의 정보를 기대하지 마라."
GROUP BY를 사용하면 집계 함수(SUM, COUNT 등)를 제외한 나머지 컬럼은 대표값 하나로 합쳐집니다. 만약 특정 조건(예: 'Y'인 행)을 찾아야 한다면, 그룹화하기 전에 WHERE로 먼저 필터링하거나, 집합 연산으로 분리하는 것이 가장 안전합니다.