집합 연산
두 쿼리 결과를 위아래로 합치거나(UNION ALL, UNION) 공통 행(INTERSECT), 한쪽에만 있는 행(MINUS)을 구하는 집합 연산자의 규칙과 업무 활용 예
#핵심 요약
집합 연산자는 네 가지임UNION ALL(합집합), UNION(합집합 + 중복 제거), INTERSECT(교집합), MINUS(차집합)
위아래 쿼리의 컬럼 수가 같아야 하고, 대응하는 컬럼은 같은 데이터 타입 그룹(숫자, 문자 등)이어야 함
집합 연산자끼리는 우선순위가 같아 왼쪽부터 평가됨
다른 순서는 괄호로 정함
실습의 활용 예: 서로 다른 집계를 한 결과로 보기, 두 테이블의 공통 고객이나 이탈 고객 찾기, 두 DB의 같은 테이블 차이 비교
#개념과 동작 원리
| 연산자 | 결과 |
|---|---|
UNION ALL |
두 결과의 모든 행 중복을 없애지 않음 |
UNION |
어느 한쪽에 있는 행을 중복 없이 |
INTERSECT |
두 쿼리 모두에 있는 행을 중복 없이 |
MINUS |
첫 쿼리에만 있고 둘째에는 없는 행을 중복 없이 |
집합 연산에서는 데이터 타입 그룹을 넘는 암시적 변환을 하지 않음
한쪽이 문자, 다른 쪽이 숫자면 오류임
한쪽 테이블에 없는 컬럼은 TO_CHAR(NULL)처럼 타입을 맞춘 NULL로 채움
ORDER BY는 맨 끝에 한 번만 씀
구성 쿼리 안에는 쓸 수 없음
앞쪽 SELECT 목록의 식으로 정렬하려면 별칭을 줌
BLOB, CLOB, BFILE, VARRAY, 중첩 테이블 컬럼에는 쓸 수 없고, UNION, INTERSECT, MINUS는 LONG 컬럼에 쓸 수 없음FOR UPDATE와 함께 쓸 수 없음
앞으로 INTERSECT의 우선순위가 높아질 예정이므로 다른 집합 연산자와 섞을 때는 괄호를 쓰라고 권함
#필수 명령어 또는 SQL
#UNION ALL로 집계 결과 합치기
SELECT deptno, SUM(sal)
FROM emp
GROUP BY deptno
UNION ALL
SELECT NULL, SUM(sal)
FROM emp
ORDER BY deptno;결과 해석: 부서별 월급 합계 아래에 전체 합계 한 행이 붙음
실습에서는 같은 결과를 GROUP BY ROLLUP(deptno)로 얻을 수 있고, 실행 계획에서 읽은 버퍼 수가 줄어든다고 설명했음ROLLUP은 다차원 집계에 있음
서로 다른 기준의 집계를 한 결과로 보기:
SELECT deptno, TO_CHAR(NULL) AS job, SUM(sal)
FROM emp
GROUP BY deptno
UNION ALL
SELECT TO_NUMBER(NULL) AS deptno, job, SUM(sal)
FROM emp
GROUP BY job
UNION ALL
SELECT TO_NUMBER(NULL), TO_CHAR(NULL), SUM(sal)
FROM emp
ORDER BY deptno, job;결과 해석:
두 배송 테이블(로켓배송, 일반배송 주문: 주문번호, 고객 이름, 상품명, 주문일)을 합쳐 배송 유형별 건수 구하기:
SELECT delivery_type, COUNT(*)
FROM (
SELECT cust_name, item_name, '로켓배송' AS delivery_type
FROM rocket_order
UNION ALL
SELECT cust_name, item_name, '일반 배송' AS delivery_type
FROM normal_order
)
GROUP BY delivery_type;결과 해석: 개별 실행 출력은 기재 없음
#INTERSECT, MINUS
실습 테이블: 회원(member), 1월, 2월 구매 이력(order_jan, order_feb), 쿠폰 대상(coupon_target), 환불 이력(refund_log), 상품 목록(product_catalog)
SELECT member_id FROM order_jan
INTERSECT
SELECT member_id FROM order_feb;
SELECT member_id FROM order_jan
MINUS
SELECT member_id FROM order_feb;
SELECT member_id
FROM coupon_target
MINUS
(
SELECT member_id FROM order_jan
UNION
SELECT member_id FROM order_feb
);결과 해석: 첫 문장은 두 달 연속 구매한 회원(충성 고객), 둘째는 1월에만 사고 2월에는 사지 않은 회원(이탈 고객), 셋째는 쿠폰을 받고 한 번도 사지 않은 회원임
셋째 문장은 괄호로 UNION을 먼저 계산함
#두 DB의 테이블 차이 비교
실습에서는 짝과 서로 DB 링크를 만들어 같은 구조의 테이블을 비교했음
SELECT * FROM emp
MINUS
SELECT * FROM emp_<INITIAL>@<LINK_NAME>;
SELECT * FROM emp_<INITIAL>@<LINK_NAME>
MINUS
SELECT * FROM emp;결과 해석: 양쪽 방향으로 실행해야 한쪽에만 있는 행과 값이 다른 행을 모두 찾음
DB 링크는 데이터베이스 링크에 있음
#사용 조건과 주의사항
바꿀 입력값: <INITIAL>, <LINK_NAME>