데이터베이스

Oracle(2022.02.25)2-집합 연산자

AIN99 2022. 2. 25. 17:43
728x90

집합연산자

 -합집합(UNION, UNION ALL),교집합(INTERSECT), 차집합(MINUS)결과를 반환하는 연산자
 -집합연산자의 대상은  SELECT문의 결과이다.
 -조인 등의 복잡한 연산을 줄일 수 있다.
 -모든 SELECT문의 컬럼의 수, 데이터타입, 순서가 일치해야함 
 -첫 SELECT문에 적용된 컬럼타입,이름이 기준이 됨 
 -CLOB,BLOB,BFILE 타입은 사용 불가
 -ORDER BY 절은 맨 마지막 SELECT문에만 사용 가능
 
 1.UNION, UNION ALL (외부조인에 해당)
 -합집합의 결과를 교집합 부분의 중복없이(UNION), 중복하여(UNION ALL) 반환한다.

   .첫번째 SELECT문의 결과와 나머지 SELECT문의 결과가 결합하여 반환

  (사용형식)
  SELECT 컬럼 list1
    FROM 테이블명
  [WHERE 조건]
  UNION|UNION ALL|INTERSECT|MINUS
  SELECT 컬럼 list2
    FROM 테이블명
  [WHERE 조건]
  UNION|UNION ALL|INTERSECT|MINUS
       :
  SELECT 컬럼 listn
    FROM 테이블명
  [WHERE 조건]  
  [ORDER BY 컬럼명];

사용예) 장바구니테이블에서 2005년 5월과 7월에 구매한 모든 회원을 조회하시오.
         Alias는 회원번호, 회원명, 주소, 마일리지이다.

 (집합연산자 사용X)
        SELECT DISTINCT A.CART_MEMBER AS 회원번호, 
               B.MEM_NAME AS 회원명, 
               B.MEM_ADD1||' '||B.MEM_ADD2 AS 주소,
               B.MEM_MILEAGE AS 마일리지
          FROM CART A, MEMBER B
         WHERE A.CART_MEMBER=B.MEM_ID
           AND SUBSTR(CART_NO,1,6) IN('200505','200507')
        ORDER BY 1;

   (집합연산자 UNION 사용O) 20명 11명 합치니까 23명 8명 겹침 
         SELECT DISTINCT A.CART_MEMBER AS 회원번호, 
               B.MEM_NAME AS 회원명, 
               B.MEM_ADD1||' '||B.MEM_ADD2 AS 주소,
               B.MEM_MILEAGE AS 마일리지
          FROM CART A, MEMBER B
         WHERE A.CART_MEMBER=B.MEM_ID
           AND SUBSTR(CART_NO,1,6) ='200505'
       UNION    
            SELECT DISTINCT A.CART_MEMBER ,
               B.MEM_NAME AS, 
               B.MEM_ADD1||' '||B.MEM_ADD2 ,
               B.MEM_MILEAGE 
          FROM CART A, MEMBER B
         WHERE A.CART_MEMBER=B.MEM_ID
           AND SUBSTR(CART_NO,1,6) ='200507'
         ORDER BY 1;

200505
200507

 

 (집합연산자 UNION ALL 사용O) 31건 반환 8명 중복된거 포함 
      SELECT DISTINCT A.CART_MEMBER AS 회원번호, 
               B.MEM_NAME AS 회원명, 
               B.MEM_ADD1||' '||B.MEM_ADD2 AS 주소,
               B.MEM_MILEAGE AS 마일리지
          FROM CART A, MEMBER B
         WHERE A.CART_MEMBER=B.MEM_ID
           AND SUBSTR(CART_NO,1,6) ='200505'
       UNION ALL    
            SELECT DISTINCT A.CART_MEMBER ,
               B.MEM_NAME AS, 
               B.MEM_ADD1||' '||B.MEM_ADD2 ,
               B.MEM_MILEAGE 
          FROM CART A, MEMBER B
         WHERE A.CART_MEMBER=B.MEM_ID
           AND SUBSTR(CART_NO,1,6) ='200507'
         ORDER BY 1;


사용예) 2005년 2월과 6월 매입된 상품을 모두 조회하시오.
       Alias는 상품코드, 상품명


     

(집합연산자 사용X)
       SELECT DISTINCT A.BUY_PROD AS 상품코드,
              B.PROD_NAME AS 상품명
       FROM BUYPROD A,PROD B
       WHERE A.BUY_DATE BETWEEN TO_DATE('20050201') 
             AND LAST_DAY(TO_DATE('20050201'))
             AND A.BUY_PROD=B.PROD_ID
             
        SELECT DISTINCT A.BUY_PROD AS 상품코드,
              B.PROD_NAME AS 상품명
       FROM BUYPROD A,PROD B
       WHERE A.BUY_DATE BETWEEN TO_DATE('20050601') 
             AND LAST_DAY(TO_DATE('20050601'))
             AND A.BUY_PROD=B.PROD_ID;

2월 데이터 일부
5월 데이터일부

(집합연산자 UNION 사용O) 41가지중 6가지 중복 제외하고 출력
      SELECT DISTINCT A.BUY_PROD AS 상품코드,
              B.PROD_NAME AS 상품명
       FROM BUYPROD A,PROD B
       WHERE A.BUY_DATE BETWEEN TO_DATE('20050201') 
             AND LAST_DAY(TO_DATE('20050201'))
             AND A.BUY_PROD=B.PROD_ID
       UNION      
        SELECT DISTINCT A.BUY_PROD AS 상품코드,
              B.PROD_NAME AS 상품명
       FROM BUYPROD A,PROD B
       WHERE A.BUY_DATE BETWEEN TO_DATE('20050601') 
             AND LAST_DAY(TO_DATE('20050601'))
             AND A.BUY_PROD=B.PROD_ID
       ORDER BY 1;

 (집합연산자 INTERSECT 사용O) 6가지가 중복된 갯수(2월도 6월도)
     SELECT DISTINCT A.BUY_PROD AS 상품코드,
              B.PROD_NAME AS 상품명
       FROM BUYPROD A,PROD B
       WHERE A.BUY_DATE BETWEEN TO_DATE('20050201') 
             AND LAST_DAY(TO_DATE('20050201'))
             AND A.BUY_PROD=B.PROD_ID
       INTERSECT      
        SELECT DISTINCT A.BUY_PROD AS 상품코드,
              B.PROD_NAME AS 상품명
       FROM BUYPROD A,PROD B
       WHERE A.BUY_DATE BETWEEN TO_DATE('20050601') 
             AND LAST_DAY(TO_DATE('20050601'))
             AND A.BUY_PROD=B.PROD_ID
       ORDER BY 1;


2.INTERSECT
 -교집합의 결과를 반환

사용예) 사원테이블과 직무변동테이블(JOB_HISTORY)에서 사원번호와
       직책코드가 같은 사원을 조회하시오   

(집합연산자 사용 X)
       SELECT  A.EMPLOYEE_ID AS 사원번호,
               A.EMP_NAME AS 사원명,
               A.JOB_ID AS 직책코드
         FROM  HR.EMPLOYEES A
        WHERE (A.EMPLOYEE_ID,A.JOB_ID )=ANY (SELECT EMPLOYEE_ID,JOB_ID
                                            FROM HR.JOB_HISTORY)
                                            
 (또 다른 코드)
 
       SELECT  A.EMPLOYEE_ID AS 사원번호,
               A.EMP_NAME AS 사원명,
               B.JOB_ID AS 직책코드
             FROM  HR.EMPLOYEES A,( SELECT EMPLOYEE_ID,JOB_ID
                                      FROM HR.JOB_HISTORY)B
            WHERE A.JOB_ID=B.JOB_ID
              AND A.EMPLOYEE_ID=B.EMPLOYEE_ID;

      
쌍으로 비교가 되어야 하는데 앞이 사원번호, 직업번호 순서로 양쪽에서나온 행을 비교해야한다. 하지만 오른쪽은 결과가 10개이므로 관계연산자 '='를 사용X 다중연산자를 사용해야한다.                                                   
 즉'=': 1명분의 자료 VS 10줄이므로 사용이 안되고 ANY를 써야한다. (확인해보니 IN,=SOME다 가능한듯)
        

 (집합연산자를 사용O)
        SELECT  A.EMPLOYEE_ID AS 사원번호,
                A.JOB_ID AS 직책코드
         FROM  HR.EMPLOYEES A 
     INTERSECT    
         SELECT EMPLOYEE_ID,
                JOB_ID
          FROM HR.JOB_HISTORY;

 (오류 주의- 위에는 3개 밑에는 2개 개수가 맞아야한다.)
        SELECT  A.EMPLOYEE_ID AS 사원번호,
                A.EMP_NAME AS 사원명,
                A.JOB_ID AS 직책코드
         FROM  HR.EMPLOYEES A 
     INTERSECT    
         SELECT EMPLOYEE_ID,
                JOB_ID
          FROM HR.JOB_HISTORY;


사용예) 2005년 4월과 5월 6월에 공통으로 판매된 상품을 모두 조회하시오.
       Alias는 상품코드, 상품명
 

사용예) 2005년 4월과 5월 6월에 공통으로 판매된 상품을 모두 조회하시오.
       Alias는 상품코드, 상품명
    (EXISTS 연산자 사용)
    --2005년 4월에 판매된 상품코드와 상품명 조회
    SELECT DISTINCT A.CART_PROD AS 상품코드,
           B.PROD_NAME AS 상품명
      FROM CART A, PROD B
      WHERE A.CART_PROD=B.PROD_ID
        AND A.CART_NO LIKE '200504%'
    --2005년 5월에 판매된 상품코드와 상품명 조회
     SELECT DISTINCT CART_PROD AS BID
      FROM CART 
     WHERE CART_NO LIKE '200505%'
     --2005년 6월에 판매된 상품코드와 상품명 조회
     SELECT DISTINCT CART_PROD AS CID     
      FROM CART
     WHERE CART_NO LIKE '200506%'

4월
5월
6월

 --서브쿼리를 사용한 결합 2005년 6월 판매된 상품코드가 5월 상품코드같은거 참 2005년 5월 상품코드가 2005년 4월상품코드랑 같고 그러면 출력해
     SELECT DISTINCT A.CART_PROD AS 상품코드,
           B.PROD_NAME AS 상품명
      FROM CART A, PROD B
      WHERE A.CART_PROD=B.PROD_ID
        AND A.CART_NO LIKE '200504%'
        AND EXISTS ( SELECT 1
                       FROM CART C
                      WHERE CART_NO LIKE '200505%'
                        AND C.CART_PROD=A.CART_PROD
                        AND EXISTS(SELECT 1    
                                     FROM CART D
                                    WHERE CART_NO LIKE '200506%'
                                      AND D.CART_PROD=C.CART_PROD))
      ORDER BY 1;

(집합연산자 INTERSECT 사용)
     SELECT DISTINCT A.CART_PROD AS 상품코드,
           B.PROD_NAME AS 상품명
      FROM CART A, PROD B
      WHERE A.CART_PROD=B.PROD_ID
        AND A.CART_NO LIKE '200504%'
 INTERSECT       
     SELECT DISTINCT A.CART_PROD,
           B.PROD_NAME 
      FROM CART A, PROD B
      WHERE A.CART_PROD=B.PROD_ID
        AND A.CART_NO LIKE '200505%'
 INTERSECT       
     SELECT DISTINCT A.CART_PROD,
           B.PROD_NAME 
      FROM CART A, PROD B
      WHERE A.CART_PROD=B.PROD_ID
        AND A.CART_NO LIKE '200506%'
      ORDER BY 1;

 (결합(서브쿼리+집합연산자))
    SELECT DISTINCT A.CART_PROD AS 상품코드,
           B.PROD_NAME AS 상품명
      FROM CART A, PROD B
      WHERE A.CART_PROD=B.PROD_ID
        AND A.CART_NO LIKE '200504%'
        AND A.CART_PROD IN ( SELECT DISTINCT CART_PROD 
                              FROM CART 
                            WHERE CART_NO LIKE '200505%'
                      INTERSECT
                            SELECT DISTINCT CART_PROD
                              FROM CART 
                             WHERE CART_NO LIKE '200506%')
      ORDER BY 1;


3. MINUS(차집합)
 - 복수개의 쿼리결과에 대하여 차집합의 결과 반환


사용예)매입테이블에서 2005년 1월과 4월의 매입을 비교하여 1월에만 매입된 상품정보를
      출력 하시오(단, 동일 상품의 메입가격이 1월과 4월이 다른경우도 있음)
      Alias는 상품코드,매입가,매입수량합계

--1월 상품별 매입수량 1월 결과 밖에 안나옴 BUY_PROD,SUM(BUY_QTY)이 같은것을 빼야하는데 1월39,4월26 SUM개수 달라서 하나도 안뺴짐 오류!
      SELECT BUY_PROD,
             SUM(BUY_QTY)
        FROM BUYPROD
       WHERE BUY_DATE BETWEEN '20050101' AND '20050131'
       GROUP BY BUY_PROD
 MINUS      
       SELECT BUY_PROD,
             SUM(BUY_QTY)
        FROM BUYPROD
       WHERE BUY_DATE BETWEEN '20050401' AND '20050430'
       GROUP BY BUY_PROD
       ORDER BY BUY_PROD;
728x90