모던지 / SQL 개발자 / SQL 기본 및 활용 9강. 집합 연산자

SQL 기본 및 활용 9강. 집합 연산자

조인은 옆으로 붙이고 집합 연산자는 위아래로 쌓습니다. 둘을 혼동하면 컬럼 수가 맞지 않는다는 오류로 배우게 됩니다.

풀고 시작

문제 1. 집합 연산자를 사용할 때 지켜야 하는 조건으로 옳은 것은?
위아래로 쌓는 연산이므로 열의 개수와 자료형만 맞으면 됩니다. 컬럼 이름은 달라도 되고 결과의 컬럼 이름은 첫 번째 질의의 것을 따릅니다.

위아래로 쌓는 연산

조인이 두 집합을 옆으로 이어 컬럼을 늘리는 일이라면, 집합 연산자는 두 결과를 위아래로 쌓아 행을 늘리는 일입니다. 그래서 요구 조건도 다릅니다. 조인은 이을 고리가 필요하지만 집합 연산자는 열의 모양이 맞아야 합니다.

구체적으로는 두 가지입니다. 컬럼 개수가 같아야 하고, 대응하는 위치의 컬럼끼리 자료형이 호환되어야 합니다. 컬럼 이름은 같지 않아도 됩니다. 결과에 나오는 컬럼 이름은 첫 번째 질의의 것을 씁니다. 그래서 두 번째 질의에만 별칭을 붙여 놓고 결과에 안 나온다고 당황하는 일이 생기죠.

네 가지 연산자

연산자 중복 처리
UNION 두 결과의 합집합 중복을 제거합니다
UNION ALL 두 결과를 그대로 이어 붙임 중복을 제거하지 않습니다
INTERSECT 두 결과에 모두 있는 행 중복을 제거합니다
EXCEPT (MINUS) 앞에는 있고 뒤에는 없는 행 중복을 제거합니다

UNION과 UNION ALL의 차이가 가장 자주 나옵니다. UNION은 중복을 없애기 위해 내부적으로 정렬이나 해시 작업을 하므로 UNION ALL보다 비쌉니다. 그래서 두 결과가 애초에 겹칠 수 없는 경우, 예컨대 기간을 나눠 뽑은 두 결과를 합칠 때는 UNION ALL을 쓰는 편이 훨씬 빠릅니다. 실무에서 습관적으로 UNION을 쓰는 것이 성능을 깎아먹는 흔한 자리입니다.

차집합을 뜻하는 연산자는 이름이 갈립니다. 표준은 EXCEPT이고 일부 제품은 MINUS를 씁니다. 뜻은 같고, 순서가 결과를 바꾼다는 점을 기억해 두세요. 합집합과 교집합은 앞뒤를 바꿔도 결과가 같지만 차집합은 다릅니다.

정렬은 마지막에 한 번만

집합 연산자로 여러 질의를 묶었을 때 ORDER BY는 문장의 맨 마지막에 한 번만 쓸 수 있습니다. 개별 질의마다 정렬을 붙일 수 없습니다. 생각해 보면 당연합니다. 쌓아 놓고 다시 순서를 정할 것이니 안쪽에서 미리 줄을 세워도 의미가 없죠.

이때 정렬 기준으로는 첫 번째 질의의 컬럼명이나 별칭, 또는 컬럼 순번을 씁니다. 두 번째 질의의 컬럼 이름은 결과에 존재하지 않으니 쓸 수 없습니다. 컬럼 이름이 서로 다를 때는 순번을 쓰는 편이 확실합니다.

우선순위도 알아 둘 만합니다. 여러 집합 연산자를 이어 쓰면 위에서 아래로 차례대로 처리되는 것이 기본이고, 순서를 바꾸려면 괄호를 씁니다. 다만 일부 제품은 교집합에 더 높은 우선순위를 두므로, 세 개 이상을 섞을 때는 괄호로 의도를 못 박아 두는 편이 안전합니다.

어떤 문제가 집합 연산자로 풀리나

집합 연산자가 자연스러운 상황은 몇 가지로 정리됩니다.

성격이 다른 여러 테이블에서 같은 모양의 목록을 만들 때입니다. 개인 회원과 법인 회원이 별도 테이블에 있는데 하나의 회원 목록으로 보여 줘야 하는 경우죠. 이때 어느 쪽에서 왔는지 구분할 컬럼을 상수로 붙여 주면 결과를 읽기 쉬워집니다.

두 시점의 데이터를 비교할 때입니다. 어제 목록과 오늘 목록의 차집합을 구하면 새로 생긴 건과 사라진 건을 각각 뽑을 수 있습니다. 방향을 바꿔 두 번 실행하는 것이 요령입니다.

FULL OUTER JOIN을 흉내 낼 때입니다. 7강에서 말한 그 이야기입니다. 방향이 다른 두 외부 조인을 UNION으로 묶으면 양쪽의 짝 없는 행이 모두 남고, UNION이 중복을 없애 주므로 양쪽에 다 있는 행이 두 번 나오지도 않습니다.

반대로 집합 연산자로 풀지 않는 편이 나은 경우도 있습니다. 같은 테이블을 조건만 달리해 여러 번 읽고 합치는 쿼리는 대개 CASE 식 하나로 줄일 수 있습니다. 테이블을 세 번 읽는 대신 한 번 읽고 분기하는 것이니 훨씬 가볍죠. 10강에서 볼 그룹 함수와 11강의 윈도우 함수도 이 계열의 개선을 자주 만들어 줍니다.

인출 문제

문제 1. 두 질의의 결과가 겹칠 가능성이 전혀 없을 때 UNION 대신 UNION ALL을 쓰는 이유는?
중복이 없다는 것을 아는 상황에서 중복 제거 작업은 순수한 낭비입니다. UNION은 그 작업을 위해 정렬이나 해시를 수행하므로 UNION ALL보다 느립니다.
문제 2. 집합 연산자로 묶은 질의에서 ORDER BY에 대한 설명으로 옳은 것은?
쌓은 결과 전체에 대해 마지막에 한 번 정렬합니다. 결과의 컬럼 이름은 첫 번째 질의를 따르므로 정렬 기준도 그쪽 이름이나 컬럼 순번을 씁니다.
문제 3. 다음 중 앞뒤 질의의 순서를 바꾸면 결과가 달라지는 연산자는?
차집합은 앞에는 있고 뒤에는 없는 행을 남기므로 방향이 결과를 결정합니다. 합집합과 교집합은 앞뒤를 바꿔도 같은 집합이 나옵니다.
문제 4. 집합 연산자 사용 시 결과의 컬럼 이름은 어떻게 정해지나?
결과의 열 이름은 첫 번째 질의가 정합니다. 그래서 두 번째 질의에만 별칭을 붙여도 결과에 나타나지 않습니다.

더 풀기

출제기준의 세세항목을 따라 이 강의 범위에서 새로 낸 문제입니다. 모의고사도 여기에서 뽑습니다.

묶음 1

문제 1. 집합 연산자와 조인의 근본적인 차이로 가장 알맞은 것은?
방향이 다릅니다. 조인은 컬럼이 늘고 집합 연산은 행이 늡니다.
문제 2. 집합 연산자를 쓰기 위한 조건으로 옳은 것은?
개수와 자료형이 맞아야 쌓을 수 있습니다. 컬럼 이름은 달라도 되며 결과의 이름은 첫 질의를 따릅니다.
문제 3. 집합 연산의 결과에서 컬럼 이름은 어느 질의를 따르나요?
첫 질의의 컬럼 이름과 별칭이 결과의 이름이 됩니다. 그래서 별칭은 첫 질의에 붙여야 의미가 있습니다.
문제 4. UNION 연산자의 동작으로 옳은 것은?
UNION은 합집합이며 중복을 제거합니다. 그 과정에서 정렬이나 해시 작업이 일어나 비용이 듭니다.
문제 5. UNION ALL의 동작으로 옳은 것은?
중복 제거 작업이 없으므로 UNION보다 대개 빠릅니다. 중복이 없다는 것을 알고 있다면 이쪽을 쓰는 편이 좋습니다.
문제 6. 결과 A가 5행, 결과 B가 3행이고 겹치는 행이 2행일 때 UNION의 결과 행 수는?
합치면 여덟이지만 겹친 두 행이 하나씩 줄어 여섯이 됩니다.
문제 7. 같은 상황에서 UNION ALL의 결과 행 수는?
중복을 제거하지 않으므로 다섯과 셋을 그대로 더한 여덟입니다.
문제 8. 같은 상황에서 교집합 연산의 결과 행 수는?
양쪽에 모두 있는 두 행만 남습니다.
문제 9. 같은 상황에서 A에서 B를 뺀 차집합의 결과 행 수는?
다섯 행 중 겹친 두 행이 빠져 세 행입니다.
문제 10. 차집합 연산에서 순서를 바꾸면 결과가 달라지나요?
합집합과 교집합은 순서를 바꾸어도 같지만 차집합은 다릅니다. 위 예에서 반대로 빼면 한 행이 됩니다.

묶음 2

문제 1. UNION을 쓸 때 중복 제거 때문에 생기는 부작용으로 가장 알맞은 것은?
중복 판단은 선택한 컬럼 조합으로만 이루어집니다. 구분되는 컬럼을 빼고 조회하면 서로 다른 행이 사라집니다.
문제 2. 중복이 없다는 것을 아는데도 UNION을 쓰면 생기는 문제는?
결과는 같지만 일하는 양이 다릅니다. 이럴 때는 UNION ALL이 정답입니다.
문제 3. 집합 연산자를 쓴 질의에서 ORDER BY는 어디에 쓸 수 있나요?
정렬은 합쳐진 최종 결과에 적용됩니다. 그래서 문장 맨 끝에 한 번만 씁니다.
문제 4. 집합 연산자를 쓴 질의의 ORDER BY에서 정렬 기준으로 쓸 수 있는 것은?
최종 결과에 없는 컬럼으로는 정렬할 수 없습니다. 첫 질의의 컬럼 이름이나 순서 번호를 씁니다.
문제 5. 집합 연산에서 NULL은 중복 판정에서 어떻게 취급되나요?
비교 연산에서는 NULL끼리 같다고 하지 않지만 중복 제거와 그룹화에서는 같은 것으로 묶습니다. 규칙이 다르다는 점을 기억해야 합니다.
문제 6. 여러 집합 연산자를 한 문장에 함께 쓸 때 처리 순서로 옳은 것은?
우선순위 규칙이 제품마다 다를 수 있습니다. 괄호를 쓰면 어디서든 같은 결과가 나옵니다.
문제 7. 두 질의의 컬럼 개수가 다르면 어떻게 되나요?
개수가 맞아야 쌓을 수 있습니다. 부족하면 NULL이나 상수를 명시적으로 채워 개수를 맞춰야 합니다.
문제 8. 컬럼 개수를 맞추기 위해 한쪽에 값을 채워 넣을 때 쓰는 방법으로 알맞은 것은?
자리만 맞으면 되므로 상수나 NULL을 넣습니다. 다만 자료형이 호환되어야 합니다.
문제 9. 서로 다른 두 테이블에서 같은 성격의 데이터를 한 목록으로 보고 싶을 때 가장 알맞은 방법은?
같은 모양의 행을 모으는 일이므로 쌓아야 합니다. 조인은 서로 다른 성격의 정보를 옆으로 붙일 때 씁니다.
문제 10. 올해 주문 테이블과 작년 주문 테이블이 따로 있을 때 두 해를 함께 조회하려면?
같은 구조의 행이 서로 다른 테이블에 나뉘어 있을 뿐입니다. 쌓아 올리면 하나의 목록이 됩니다.

묶음 3

문제 1. 두 해의 주문 테이블을 이어 붙일 때 UNION과 UNION ALL 중 무엇을 써야 하나요?
겹칠 일이 없으면 중복 제거는 낭비입니다. 다만 정말 겹치지 않는지는 확인해야 합니다.
문제 2. 집합 연산자로 차집합을 구하는 것과 NOT EXISTS로 구하는 것의 차이로 가장 알맞은 것은?
비교 기준이 다릅니다. 키 하나로만 비교하고 싶다면 NOT EXISTS가 적합합니다.
문제 3. 집합 연산의 결과에 중복이 남아 있다면 어떤 연산자를 쓴 것인가요?
중복을 남기는 것은 UNION ALL뿐입니다. 나머지 연산자는 모두 중복을 제거합니다.
문제 4. 교집합 연산의 결과에 중복 행이 나타날 수 있나요?
교집합도 중복을 제거한 집합을 돌려줍니다.
문제 5. 집합 연산자를 쓴 질의에서 각 질의마다 WHERE 절을 쓸 수 있나요?
합치기 전까지는 별개의 질의입니다. 조건도 정렬을 제외하면 각자 쓸 수 있습니다.
문제 6. 각 질의에 GROUP BY를 쓸 수 있나요?
각 질의가 만들어 낸 결과 집합을 쌓는 것이므로 그 안에서 무엇을 하든 상관없습니다.
문제 7. 대응하는 컬럼의 자료형이 문자와 숫자로 서로 다르면 어떻게 되나요?
제품에 따라 일부 변환은 허용되지만 의도치 않은 변환은 위험합니다. 명시적으로 맞추는 편이 안전합니다.
문제 8. UNION ALL로 여러 테이블을 합친 뒤 전체를 그룹으로 묶으려면?
각각 묶으면 테이블별 결과가 따로 나옵니다. 전체 기준으로 묶으려면 합친 결과를 하나의 대상으로 삼아야 합니다.
문제 9. 어떤 문제가 집합 연산자로 자연스럽게 풀리나요?
조건별 결과를 하나의 목록으로 만들 때 쌓기가 자연스럽습니다. 조건마다 구분 값을 상수로 붙이면 어느 조건에서 나왔는지도 알 수 있습니다.
문제 10. 다음 중 집합 연산자에 대한 설명으로 옳지 않은 것은?
이름은 달라도 됩니다. 결과의 이름은 첫 질의를 따릅니다.

이전: 8강 서브쿼리 · 다음: 10강 그룹 함수

모던지 · 궁금하면 모던지 GitHub · 2026-09-10