제2절_집합_연산자(SET_OPERATOR)

조회 수 12219 추천 수 0 2013.09.05 09:42:10
실천하자 *.18.78.25

2. 집합 연산자(SET_OPERATOR)

- 연관된 데이터를 조회하는 방법 중 하나
- 여러 개의 질의의 결과를 연결하여 하나로 결합하는 방식 사용

   ☞ 즉, 집합 연산자는 2개 이상의 질의 결과를 하나의 결과로 만들어 준다. 

■ 일반적으로 집합 연산자를 사용하는 상황

  • 서로 다른 테이블에서 유사한 형태의 결과를 반환하는 것을 하나의 결과로 합치고자 할 때 사용
  • 동일 테이블에서 서로 다른 질의를 수행하여 결과를 합치고자 할 때 사용
  • 이외에도 튜닝관점에서 실행계획을 분리하고자 하는 목적으로도 사용

■ 집합 연산자를 사용하기 위한 제약조건 (조건을 지키지 않을 시 데이터베이스가 오류 반환)

  • SELECT 절의 칼럼 수가 동일
  • SELECT 절의 동일 위치에 존재하는 칼럼의 데이터 타입이 상호 호환 가능 (반드시 동일한 데이터 타입일 필요는 없음)

집합 연산자는 개별 SQL문의 결과 집합에 대해 합집합(UNION/UNION ALL), 교집합(INTERSECT), 차집합(EXCEPT)으로 집합간의 관계를 가지고 작업

가장 왼쪽에 존재하는 R1, R2는 각각의 SQL문을 실행해서 생성된 개별 결과 집합 의미

R1 = { 1, 2, 3, 5 }            R2 = { 1, 2, 3, 4 }


UNION ALL을 제외한 다른 집합 연산자에서는 

SQL문의 결과 집합에서 먼저 중복된 건을 배제하는 작업을 수행한 후에 집합 연산을 적용 (논리적인 관점의 처리임)

  • UNION 연산 : 합집합(R1 ∪ R2)의 결과는 {1, 2, 3, 4, 5}
  • UNION ALL 연산 : 중복에 대한 배제 없이 2개의 결과 집합을 단순히 합친 것과 동일 

              결과 {1, 1, 1, 2, 2, 3, 3, 5, 1, 1, 2, 2, 2, 3, 4}

  • INTERSECT 연산 : 교집합(R1 ∩ R2)의 결과는 {1, 2, 3}
  • EXCEPT 연산 : 차집합(R1 - R2)의 결과는 {5}

    ※ EXCEPT 연산에서는 순서 주의 : 차집합(R2 - R1)의 결과는 {4}


▼ 문법

SELECT 칼럼명1, 칼럼명2, ... 

FROM 테이블명1 

WHERE 조건식 ] [[GROUP BY 칼럼(Column)이나 표현식 [HAVING 그룹조건식 ] ] 

집합 연산자 

SELECT 칼럼명1, 칼럼명2, ... 

FROM 테이블명2 

WHERE 조건식 ] [[GROUP BY 칼럼(Column)이나 표현식 [HAVING 그룹조건식 ] ] 

ORDER BY 1, 2 [ASC 또는 DESC ] ; 


    ▼ 예제

SELECT PLAYER_NAME 선수명, BACK_NO 백넘버 

FROM  PLAYER 

WHERE TEAM_ID = 'K02' 

UNION 

SELECT PLAYER_NAME 선수명, BACK_NO 백넘버 

FROM  PLAYER 

WHERE TEAM_ID = 'K07' 

ORDER BY 1;

  • 집합 연산자는 사용상의 제약조건을 만족한다면 어떤 형태의 SELECT문이라도 이용가능
  • 집합 연산자는 여러 개의 SELECT문을 연결하는 것에 지나지 않음
  • ORDER BY는 집합 연산을 적용한 최종 결과에 대한 정렬 처리이므로 가장 마지막 줄에 한번만 기술


■ 예제 1 - 'UNION' vs 'OR 연산자' / 'IN List'

 질문 

 K-리그 소속 선수들 중에서 소속이 삼성블루윙즈팀인 선수들과                                                 

 전남드레곤즈팀인 선수들에 대한 내용을 모두 보고 싶다. 

집합

 K-리그 소속 선수 중 소속이 삼성블루윙즈팀인 선수들의 집합과

 K-리그 소속 선수 중 소속이 전남드레곤즈팀인 선수들의 집합의 합집합

쿼리

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE TEAM_ID = 'K02'

 UNION

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE TEAM_ID = 'K07'

비교

쿼리

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE TEAM_ID = 'K02' OR TEAM_ID = 'K07'

비교

쿼리

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE TEAM_ID IN ('K02', 'K07')



■ 예제 2 - 'UNION' vs 'UNION ALL'

 질문 

 K-리그 소속 선수들 중에서 소속이 삼성블루윙즈팀인 선수들과                                                 

 포지션이 골키퍼(GK)인 선수들을 모두 보고 싶다.

집합

 K-리그 소속 선수 중 소속이 삼성블루윙즈팀인 선수들의 집합과

 K-리그 소속 선수 중 포지션이 골키퍼(GK)인 선수들의 집합의 합집합

쿼리

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE TEAM_ID = 'K02'

 UNION

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE POSITION = 'GK'

비교

쿼리

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE TEAM_ID = 'K02'

 UNION ALL

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE POSITION = 'GK'



■ 예제 3 - 각 집합의 구분

질문

 K-리그 소속 선수들에 대한 정보 중에서 포지션별 평균키와 팀별 평균키를 알고 싶다.

 집합 

 K-리그 소속 선수 중 포지션별 평균키에 대한 집합과 K-리그 소속 선수 중 팀별 평균키에 대한 집합의 합집합     

쿼리

 SELECT 'P' 구분코드, POSITION 포지션, AVG(HEIGHT) 평균키

 FROM PLAYER

 GROUP BY POSITION

 UNION

 SELECT 'T' 구분코드, TEAM_ID 팀명, AVG(HEIGHT) 평균키

 FROM PLAYER

 GROUP BY TEAM_ID

 ORDER BY 1



■ 예제 4 - 'MINUS'('EXCEPT') vs '<>' / 'NOT EXISTS 서브쿼리' / 'NOT IN 서브쿼리'

질문

 K-리그 소속 선수를 중에서 소속이 삼성블루윙즈팀이면서

 포지션이 미드필더(MF)가 아닌 선수들의 정보를 보고 싶다.  

 집합 

 K-리그 소속 선수 중 소속이 삼성블루윙즈팀인 선수들의 집합과

 K-리그 소속 선수 중 포지션이 미드필더(MF)인 선수들의 집합의 차집합                                         

쿼리

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE TEAM_ID = 'K02'

 MINUS

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE POSITION = 'MF'

 ORDER BY 1, 2, 3, 4, 5

비교

쿼리

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE TEAM_ID = 'K02' AND POSITION <> 'MF'

 ORDER BY 1, 2, 3, 4, 5

비교

쿼리

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER X

 WHERE X.TEAM_ID = 'K02' AND

        NOT EXISTS (SELECT 1 FROM PLAYER Y WHERE Y.PLAYER_ID = X.PLAYER_ID AND POSITION = 'MF')

 ORDER BY 1, 2, 3, 4, 5

비교

쿼리

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE TEAM_ID = 'K02' AND

        PLAYER_ID NOT IN (SELECT PLAYER_ID FROM PLAYER WHERE POSITION = 'MF')

 ORDER BY 1, 2, 3, 4, 5



■ 예제 5 - 'INTERSECT' vs 'AND =' / 'EXISTS 서브쿼리' / 'IN List 서브쿼리'

질문

 K-리그 소속 선수들 중에서 소속이 삼성블루윙즈팀이면서 포지션이 골키퍼(GK)인 선수들의 정보를 보고 싶다.     

집합

 K-리그 소속 선수 중 소속이 삼성블루윙즈팀인 선수들의 집합과

 K-리그 소속 선수 중 포지션이 골키퍼(GK)인 선수들의 집합의 교집합

 쿼리 

 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

비교

쿼리

 SELECT TEAM_ID 팀코드, PLAYER_NAME 선수명, POSITION 포지션, BACK_NO 백넘버, HEIGHT 키

 FROM PLAYER

 WHERE TEAM_ID = 'K02' AND POSITION = 'GK'

 ORDER BY 1, 2, 3, 4, 5

비교

쿼리

 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

비교

쿼리

 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



※ 자료출처 : DBguide.Net

http://www.dbguide.net/db.db?cmd=view&boardUid=148199&boardConfigUid=9&categoryUid=216&boardIdx=135&boardStep=1


  • SQL 개발자 자격증 (bysql.net 2011년 2차 스터디)
  • 작성자: 위충환 (실천하자)
  • 최초작성일: 2011년 10월 11 일
  • 본문서는 bysql.net 스터디 결과입니다 .본 문서를 인용하실때는 출처를 밝혀주세요. http://www.bysql.net
  • 문서의 잘못된 점이나 질문사항은 본 문서에 댓글로 남겨주세요. ^^


profile

실천하자

2011.10.13 15:20:50
*.18.78.25

컬럼 수를 동일하게 한다는 조건으로, 아래와 같은 상황에서 오류가 발생하는 것은? (답은 1개 이상)

1. 동일한 컬럼의 별칭을 다르게하여 매칭

2. 같은 자료형과 같은 길이지만 다른 컬럼 매칭

3. 같은 자료형이지만 길이가 다른 컬럼 매칭

4. 다른 자료형의 컬럼 매칭

5. 다른 자료형이지만 형변환하여 컬럼 매칭


교제 내용 외 집합연산 시 한 번은 위의 예제를 고민해보고 실습해보자!!


-- 1.확인

SELECT ENAME 사원명, EMPNO 사번 

FROM SCOTT.EMP WHERE MGR IS NULL

UNION

SELECT ENAME 사원이름, EMPNO 사원번호 

FROM SCOTT.EMP WHERE ENAME = 'SCOTT'


-- 2.확인 -- EMPNO NUMBER(4), MGR NUMBER(4)

SELECT '본인' 구분, EMPNO 사번, ENAME 사원명 

FROM SCOTT.EMP WHERE ENAME = 'SCOTT'

UNION

SELECT '메니저' 구분, MGR 사번, ENAME 사원명 

FROM SCOTT.EMP WHERE ENAME = 'SCOTT'


-- 3.확인 -- EMPNO NUMBER(4), DEPTNO NUMBER(2)

SELECT '사원' 구분, EMPNO 코드, ENAME 사원명 

FROM SCOTT.EMP WHERE ENAME = 'SCOTT'

UNION

SELECT '부서' 구분, DEPTNO 코드 , ENAME 사원명 

FROM SCOTT.EMP WHERE ENAME = 'SCOTT'


-- 4.확인 -- JOB VARCHAR2(9), DEPTNO NUMBER(2)

SELECT '직업' 구분, JOB 코드, ENAME 사원명 

FROM SCOTT.EMP WHERE ENAME = 'SCOTT'

UNION

SELECT '부서' 구분, DEPTNO 코드 , ENAME 사원명 

FROM SCOTT.EMP WHERE ENAME = 'SCOTT'


-- 5.확인 -- JOB VARCHAR2(9), DEPTNO NUMBER(2)

SELECT '직업' 구분, JOB 값, ENAME 사원명 

FROM SCOTT.EMP WHERE ENAME = 'SCOTT'

UNION

SELECT '부서' 구분, TO_CHAR(DEPTNO) 값 , ENAME 사원명 

FROM SCOTT.EMP WHERE ENAME = 'SCOTT'