이전에 정리한 JOIN
과 서브쿼리
의 공통점은 기존 테이블의 정보를 조합하거나 필터링해서
원하는 형태의 하나의 결과 집합으로 만들어 낸다는 점이다
JOIN
은 테이블을 옆으로 이어붙여서 더 많은 정보들의 컬럼들을 만드는 기술이면
이번에 정리할 UNION
은 여러개의 결과 집합을 아래로 이어 붙여서 더 많은 행을 가진
하나의 집합으로 만드는 기술이다
✅ UNION
JOIN
과 달리 테이블들이 서로 연결된 관계가 아닐 때 사용UNION
을 사용할 때는 다음과 같은 규칙이 있다
UNION
으로 연결되는 모든 SELECT
문은 컬럼의 개수가 동일해야한다 (컬럼이름은 달라도됨)SELECT
문의 같은 위치에 있는 컬럼들은 서로 호환이 가능한 데이터 타입이어야 한다SELECT name, email FROM users // 컬럼 개수가 동일하고 각 컬럼들이 동일한 데이터 타입임
UNION
SELECT name, email FROM retired_users;
select user_id ,email from users u // 컬럼이 달라도되고, 같은 데이터 타입이기만 하면 합치기 가능
union
select id,name from retired_users ru;
아래 결과처럼 중복이 제거되는 것은 합치는 모든 컬럼이 동일할때만 제거된다
1, Sean@example.com -> 두개가 중복되어서 제거됨
1, sean@example.com
과 ,1, 션
은 다른 행으로 인식되기 때문에 제거 X
✅ UNION ALL
UNION
과 다르게 중복되는 행을 제거하지 않고 모두 이어붙임마케팅팀에서 두 종류의 고객에게 이벤트 안내 메일을 보내려고 한다. 첫 번째 그룹은 '전자기기' 카테고리의 상품을 구매한 이력이 있는 고객이고, 두 번째 그룹은 '서울'에 거주하는 고객이다. 두 그룹의 명단을 합쳐서 전체 발송 목록을 만든다 했을 때
문제가 있다고 하자
위와 같은 비즈니스 요구사항에서는 서울에 살면서 전가기기를 구매한 고객
은 두 그룹에 모두 속하기 때문에 중복을 허용해야한다
select u.name , u.email
from users u
join orders o
on u.user_id = o.user_id
join products p
on p.product_id = o.product_id
where p.category = '전자기기'
union all
select u.name, u.email
from users u
where u.address like '서울%';
그럼 실무에서는 UNION
vc UNION ALL
중에 어떤것을 사용할까?
UNION ALL
이 UNION
보다 속도가 빠르다
그 이유는 UNION
은 데이터베이스 내부적으로 중복을 제거하기 위해 전체 결과를 정렬한 다음
인접한 행들을 비교하여 중복을 찾아내는 과정을 거친다
만약 데이터 양이 많다면 이 정렬과 비교 작업은 엄청난 성능 저하가 발생한다
따라서 중복을 제거해야하는 명확한 요구사항이 있을때만 UNION
을 사용하자
그 외의 모든 경우는 UNION ALL
을 우선적으로 사용하자
✅ UNION 정렬
UNION
과 UNION ALL
을 사용하여 행을 합칠 때 최종 결과 집합에 대해서 정렬이 가능하다
각 SELECT
문에 정렬 (ORDER BY) 를 사용할 수는 있지만, 예상과 다른 결과가 발생하거나 오류가 생긴다
그러므로 개별적인 정렬이아닌 합쳐진 최종 결과에 대해서 맨 마지막에 ORDER BY
를 사용하자
SELECT name, email FROM users
UNION
SELECT name, email FROM retired_users
ORDER BY name; -- 최종 결과에 대한 정렬
UNION
과 UNION ALL
을 사용하여 합치면 최종결과는 항상 첫번째 SELECT
문의 컬럼이름이나
별칭만을 사용할 수 있다
SELECT name, email, created_at FROM users
UNION ALL
SELECT name, email, retired_date FROM retired_users
ORDER BY retired_date; -- (x)
SELECT name, email, created_at FROM users
UNION ALL // created_at 과 retired_date 와 같이 다른이름의 컬럼이 있으면 항상 추상적인 별칭으로 통일하자
SELECT name, email, retired_date FROM retired_users
ORDER BY created_at; -- (o)