집합 연산자란?
두 개 이상의 테이블에서 조인을 사용하지 않고 연관된 데이터를 조회하는 방법 중에 또 다른 방법이 있는데 그 방법이 바로 집합 연산자(Set Operator)를 사용하는 방법이다.
집합 연산자는 여러 개의 질의의 결과를 연결하여 하나로 결합하는 방식을 사용한다. 즉, 집합 연산자는 2개 이상의 질의 결과를 하나의 결과로 만들어 준다.
일반적으로 집합 연산자를 사용하는 상황은 아래 두 가지이다.
1. 서로 다른 테이블에서 유사한 형태의 결과를 반환하는 것을 하나의 결과로 합치고자 할 때
2. 동일 테이블에서 서로 다른 질의를 수행하여 결과를 합치고자 할 때 사용할 수 있다.
집합 연산자를 사용하기 위해서는 다음 제약조건을 만족해야 한다.
SELECT 절의 칼럼 수가 동일하고 SELECT 절의 동일 위치에 존재하는 칼럼의 데이터 타입이 상호 호환 가능 ( 동일한 데이터 타입일 필요는 없다.) 해야 한다.
집합 연산자의 종류
집합 연산자는 개별 SQL 문의 결과 집합에 대해 합집합 (UNION/UNION ALL), 교집합 (INTERSECT), 차집합(EXCEPT)으로 집합 간의 관계를 가지고 작업을 한다. ** Oracle에서 차집합은 MINUS를 사용한다.
집합 연산자의 결과는 [그림 Ⅱ-2-5]와 같다.
개별 결과집합에는 R1 쿼리와 R2쿼리의 결과가 개별적으로 어떤 데이터로 이루어져 있는지 나타내고 있다.
오른쪽 4개의 합집합, 교집합, 차집합은 어떤 데이터를 이루는지 그림으로 설명하고 있다.
합집합(UNION {ALL})
합집합을 나타내는 집합 연산자는 크게 UNION과 UNION ALL이 있다.
둘의 차이점은 ALL이라는 단어가 붙냐 안 붙냐의 차이이다. 이 차이점은 중복 데이터를 하나로 합쳐서 보여줄 것인지 아니면 중복 데이터도 모두 나타낼 것인지를 의미한다.
또, UNION은 중복 데이터를 하나로 합치는 과정에서 정렬의 부가적인 기능을 하기 때문의 집합 간에 중복 데이터가 없다면 부가적인 정렬이 없는 UNION ALL를 사용하는 것이 성능이좋다.
아래는 합집합의 예제 쿼리이다.
UNION 예제
SELECT TEAM_ID 팀코드,
PLAYER_NAME 선수명,
POSI 포지션,
BACK_NO 백넘버,
HEIGHT 키
FROM PLAYER
WHERE TEAM_ID = 'K02'
UNION -- 중복 데이터 제거
SELECT TEAM_ID 팀코드,
PLAYER_NAME 선수명,
POSI 포지션,
BACK_NO 백넘버,
HEIGHT 키
FROM PLAYER
WHERE TEAM_ID = 'K07'
UNION ALL 예제
-- K리그 소속 선수들에 대한 정보 중에서 포지션별 평균키와 팀별 평균키를 조회한다.
SELECT 'P' 구분코드,
POSITION 포지션,
AVG(HEIGHT) 평균키
FROM PLAYER
GROUP BY POSITION
UNION ALL
SELECT 'T' 구분코드, -- 임의의 구분코드로 칼럼을 생성
TEAM_ID 팀명,
AVG(HEIGHT) 평균키
FROM PLAYER
GROUP BY TEAM_ID
ORDER BY 1; -- UNION ALL 중복 데이터 포함의 결과에 1번 칼럼으로 정렬(ASC)
위 UNION ALL 쿼리 예제에서 실제로 테이블에는 존재하지 않지만 결과행을 구분하기 위해 SELECT 절에 임의의 칼럼 (구분코드)을 추가했음을 알 수 있다.
또, 집합 연산자의 결과를 표시할 때 칼럼명은 첫 번째 SQL 문에서 사용된 ALIAS가 적용된다는 것.!!!!
차집합(EXCEPT)
차집합은 R1결과에서 R2결과를 뺀 결과를 나타낸다. 아래는 차집합 EXCEPT의 예제이다.
SELECT TEAM_ID 팀코드,
PLAYER_NAME 선수명,
POSITION 포지션,
BACK_NO 백넘버,
HEIGHT 키
FROM PLAYER
WHERE TEAM_ID = 'K02'
EXCEPT
SELECT TEAM_ID 팀코드,
PLAYER_NAME 선수명,
POSITION 포지션,
BACK_NO 백넘버,
HEIGHT 키
FROM PLAYER
WHERE POSITION = 'MF'
ORDER BY 1, 2, 3, 4, 5; -- 차집합 결과의 정렬
Oracle에서는 EXCEPT대신 MINUS를 사용할 수 있다.
교집합(INTERSECT)
교집합을 나타내는 집합 연산자는 INTERSECT이다. R1결과와 R2결과에서 서로 중복되는 데이터들만 뽑아 반환한다.
SELECT TEAM_ID 팀코드,
PLAYER_NAME 선수명,
POSITION 포지션,
BACK_NO 백넘버,
HEIGHT 키
FROM PLAYER
WHERE TEAM_ID = 'K02'
INTERSECT -- 교집합.
SELECT TEAM_ID 팀코드,
PLAYER_NAME 선수명,
POSITION 포지션,
BACK_NO 백넘버,
HEIGHT 키
FROM PLAYER
WHERE POSITION = 'GK'
ORDER BY 1, 2, 3, 4, 5;
교집합 INTERSECT는 EXISTS 또는 IN 서브 쿼리를 이용한 SQL 문으로 변경 가능하다.
INTERSECT -> EXISTS
SELECT TEAM_ID 팀코드,
PLAYER_NAME 선수명,
POSITION 포지션,
BACK_NO 백넘버,
HEIGHT 키
FROM PLAYER X
WHERE X.TEAM_ID = 'K02'
AND EXISTS ( SELECT 1
FROM PLAYER Y
WHERE Y.PLAYER_ID = X.PLAYER_ID
AND Y.POSITION = 'GK'
)
ORDER BY 1, 2, 3, 4, 5;
INTERSECT -> IN
SELECT TEAM_ID 팀코드,
PLAYER_NAME 선수명,
POSITION 포지션,
BACK_NO 백넘버,
HEIGHT 키
FROM PLAYER
WHERE TEAM_ID = 'K02'
AND PLAYER_ID IN ( SELECT PLAYER_ID
FROM PLAYER
WHERE POSITION = 'GK'
)
ORDER BY 1, 2, 3, 4, 5;
UNION, UNION ALL은 그래도 어느 정도 사용하지만 INTERSECT, EXCEPT는 사용하는 상황이 많지가 않다..... 잊어버리지 않게 복습을 잘 하자....
'DataBase > SQLD,SQLP' 카테고리의 다른 글
[MSSQL] 윈도우 함수 ROW_NUMBER() 순차번호 할당 (0) | 2022.05.04 |
---|---|
[MSSQL] 윈도우 함수 RANK() OVER 다루기 / DENSE_RANK() (0) | 2022.05.04 |
[MSSQL] 서브 쿼리 SubQuery (0) | 2022.05.01 |
[SQLD/SQLP] SELECT 절 (0) | 2022.02.22 |
[SQLD/SQLP] SQL 이란? (0) | 2022.02.22 |