DBMS

[DBMS/Oracle] 조인(JOIN)

elog 2023. 3. 16. 00:00

[DBMS/Oracle] 조인(JOIN)
[DBMS/Oracle] 조인(JOIN)

조인(JOIN)

- 필요한 데이터가 여러 테이블에 분산되어 있고 각 테이블 들이 관계를 맺고 있을 때 수행하는 연산
- 관계(RELATIONSHIP)을 이용한 연산
- 구분

   . 조인연산자에 따라 동등조인(Equi Join), 비동등 조인(Non Equi Join)
   . 조인 대상에 따라 : 셀프조인(Self Join)
   . 조인 조건에 따라 : 내부조인(Inner Join), 외부조인(Outer Join), 카타시안(Cartasian, Cross Join), 세미조인(Semi Join)
   . 기타 : ANSI Join

 

1. 내부조인

- 조인조건을 만족하는 행만 결과로 반환하고 조인조건을 만족하지 않는 데이터는 무시함.


 1) 카타시안(Cartesian Product, Cross Join)

  - 조인조건이 없거나 조인조건을 잘못기술한 경우
  - 반드시 필요한 경우가 아니면 수행하지 말아야 함
  - A(a행 b열), B(c행 d열) 두 테이블에 카타시안 조인을 수행하면
    결과는 최악의 경우(조인조건이 없는 경우) a * c 행 b + d열이 반환

사용예)
    SELECT COUNT(*) FROM BUYPROD;   -- 매입테이블의 모든 행의 수
    SELECT COUNT(*) FROM CART;      -- 매출테이블의 모든 행의 수
    SELECT COUNT(*) FROM PROD;      -- 상품테이블의 모든 행의 수
    SELECT 148*207*74 FROM DUAL;

  1-2) CROSS JOIN

. ANSI에서 제공하는 Cartesian Product

(사용형식)
    SELECT 컬럼list
      FROM 테이블명1 [별칭1]
     CROSS JOIN 테이블명2 [별칭2] [ON(조인조건)]
                        :
     CROSS JOIN 테이블명n [별칭n] [ON(조인조건)]
사용예)
    SELECT COUNT(*)
      FROM BUYPROD A
     CROSS JOIN CART B
     CROSS JOIN PROD C;

 

 2) 동등조인(Equi Join)

 - 조인조건문에 사용하는 연산자가 '='인 조인

(사용형식:일반 조인)
    SELECT [테이블별칭.|테이블명.]컬럼명 [AS 컬럼별칭][,]
                        :
           [테이블별칭.|테이블명.]컬럼명 [AS 컬럼별칭]
      FROM 테이블명1 [별칭1], 테이블명2 [별칭2], [,테이블명3 [별칭3],...] 
     WHERE 조인조건
      [AND 일반조건]


     - '테이블별칭|테이블명.' : 모든 컬럼명이 다르면 생략 가능
     -- 중요!! 조인 조건의 갯수가 n-1보다 적으면 문제가 된다.
     - 사용된 테이블의 갯수가 n개일 때 '조인조건'의 갯수는 적어도 n-1개 이상이어야 함

 

(사용형식:ANSI INNER 조인)
    SELECT [테이블별칭.|테이블명.]컬럼명 [AS 컬럼별칭][,]
                        :
           [테이블별칭.|테이블명.]컬럼명 [AS 컬럼별칭]
      FROM 테이블1 [별칭1]      
     INNER JOIN 테이블2 [별칭2] ON(조인조건 [AND 일반조건])
     INNER JOIN 테이블3 [별칭3] ON(조인조건 [AND 일반조건])
                        :
    [WHERE 일반조건]


    - 테이블1과 테이블2는 반드시 직접 조인 가능해야 함
    - '[AND 일반조건]' : 해당 테이블에만 적용되는 조건 기술
    - 'WHERE 일반조건' : 공통으로 적용된 일반조건 기술
    - 테이블1과 테이블2가 조인된 결과와 테이블3이 조인됨

 

사용예) 사원테이블에서 20-40번 부서에 소속된 사원의 사원번호,사원명,부서번호,부서명,직무명을 조회하시오

(일반 조인문)
    SELECT A.EMPLOYEE_ID AS 사원번호,
           A.EMP_NAME AS 사원명,
           B.DEPARTMENT_ID AS 부서번호,
           B.DEPARTMENT_NAME AS 부서명,
           C.JOB_TITLE AS 직무명
      FROM HR.EMPLOYEES A, HR.DEPARTMENTS B, HR.JOBS C
     WHERE A.DEPARTMENT_ID=B.DEPARTMENT_ID -- 조인조건
       AND A.JOB_ID=C.JOB_ID -- 조인조건
       AND A.DEPARTMENT_ID BETWEEN 20 AND 40 -- 일반조건
     ORDER BY 3;

(ANSI JOIN)
    SELECT A.EMPLOYEE_ID AS 사원번호,
           A.EMP_NAME AS 사원명,
           B.DEPARTMENT_ID AS 부서번호,
           B.DEPARTMENT_NAME AS 부서명,
           C.JOB_TITLE AS 직무명
      FROM HR.EMPLOYEES A
     INNER JOIN HR.DEPARTMENTS B ON(A.DEPARTMENT_ID=B.DEPARTMENT_ID) -- 조인조건 
     INNER JOIN HR.JOBS C ON(A.JOB_ID=C.JOB_ID) -- 조인조건
     WHERE A.DEPARTMENT_ID BETWEEN 20 AND 40
     ORDER BY 3;

 

사용예) 2020년 4월 상품별 매출집계를 조회하시오. Alias는 상품코드,상품명,매출수량합계,매출금액합계

(일반 조인문)
    SELECT A.CART_PROD AS 상품코드,
           B.PROD_NAME AS 상품명,
           SUM(A.CART_QTY) AS 매출수량합계,
           SUM(A.CART_QTY*B.PROD_PRICE) AS 매출금액합계
      FROM CART A, PROD B
     WHERE A.CART_PROD=B.PROD_ID -- 조인조건
       AND A.CART_NO LIKE '202004%' 
     GROUP BY A.CART_PROD,B.PROD_NAME
     ORDER BY 1;

(ANSI 조인)
    SELECT A.CART_PROD AS 상품코드,
           B.PROD_NAME AS 상품명,
           SUM(A.CART_QTY) AS 매출수량합계,
           SUM(A.CART_QTY*B.PROD_PRICE) AS 매출금액합계
      FROM CART A
     INNER JOIN PROD B ON(A.CART_PROD=B.PROD_ID) -- 조인조건
     WHERE A.CART_NO LIKE '202004%'
     GROUP BY A.CART_PROD,B.PROD_NAME
     ORDER BY 1;

 

사용예) 2020년 1-6월 거래처별 매입집계를 조회하시오. Alias는 거래처코드,거래처명,매입금액 합계

(일반 조인문)
    SELECT A.BUYER_ID AS 거래처코드,
           A.BUYER_NAME AS 거래처명,
           SUM(B.BUY_QTY*C.PROD_COST) AS "매입금액 합계"
      FROM BUYER A, BUYPROD B, PROD C
     WHERE B.BUY_PROD=C.PROD_ID -- 조인조건
       AND C.PROD_BUYER=A.BUYER_ID  -- 조인조건
       AND B.BUY_DATE BETWEEN TO_DATE('20200101') AND TO_DATE('20200630')
     GROUP BY A.BUYER_ID, A.BUYER_NAME
     ORDER BY 1;
       
(ANSI FORMAT)
    SELECT A.BUYER_ID AS 거래처코드,
           A.BUYER_NAME AS 거래처명,
           SUM(B.BUY_QTY*C.PROD_COST) AS "매입금액 합계"
      FROM BUYER A
     INNER JOIN PROD C ON(C.PROD_BUYER=A.BUYER_ID) -- 조인조건
     INNER JOIN BUYPROD B ON(B.BUY_PROD=C.PROD_ID) -- 조인조건
     WHERE B.BUY_DATE BETWEEN TO_DATE('20200101') AND TO_DATE('20200630')
     GROUP BY A.BUYER_ID, A.BUYER_NAME
     ORDER BY 1;

 

문제] HR계정에서 미국 이외의 국가에 있는 부서에 근무하는 사원들을 조회하시오. Alias는 사원번호,사원명,부서코드,부서명,부서주소 (미국의 국가코드는 'US')

(일반 조인문)
    SELECT A.EMPLOYEE_ID AS 사원번호,
           A.EMP_NAME AS 사원명,
           B.DEPARTMENT_ID AS 부서코드,
           B.DEPARTMENT_NAME AS 부서명,
           C.STREET_ADDRESS||' '||C.CITY||' '||C.STATE_PROVINCE||', '|| 
           D.COUNTRY_NAME AS 부서주소,
           D.COUNTRY_ID AS 국가코드
      FROM HR.EMPLOYEES A, HR.DEPARTMENTS B, HR.LOCATIONS C, HR.COUNTRIES D
     WHERE A.DEPARTMENT_ID=B.DEPARTMENT_ID
       AND B.LOCATION_ID=C.LOCATION_ID  
       AND C.COUNTRY_ID=D.COUNTRY_ID
       AND C.COUNTRY_ID!='US'
    ORDER BY 3;    
    
(ANSI 조인)
    SELECT A.EMPLOYEE_ID AS 사원번호,
           A.EMP_NAME AS 사원명,
           B.DEPARTMENT_ID AS 부서코드,
           B.DEPARTMENT_NAME AS 부서명,
           C.STREET_ADDRESS||' '||C.CITY||' '||C.STATE_PROVINCE||', '|| 
           D.COUNTRY_NAME AS 부서주소,
           D.COUNTRY_ID AS 국가코드
      FROM HR.EMPLOYEES A
     INNER JOIN HR.DEPARTMENTS B ON(A.DEPARTMENT_ID=B.DEPARTMENT_ID)
     INNER JOIN HR.LOCATIONS C ON(B.LOCATION_ID=C.LOCATION_ID AND
           C.COUNTRY_ID!='US')
     INNER JOIN HR.COUNTRIES D ON(C.COUNTRY_ID=D.COUNTRY_ID)
    ORDER BY 3;

:

 

3) SEMI JOIN

   - 서브쿼리를 사용하여 추출된 중간결과만 메인쿼리에서 추출하는 조인
   - IN과 EXISTS 연산자 사용

 

사용예) 사원테이블에서 급여가 10000이상되는 사원이 있는 부서정보를 조회하시오. Alias는 부서코드, 부서명

(EXISTS 연산)
    SELECT A.DEPARTMENT_ID AS 부서코드,
           A.DEPARTMENT_NAME AS 부서명
      FROM HR.DEPARTMENTS A
     WHERE EXISTS (SELECT 1 -- 서브쿼리, 서브쿼리 먼저 실행, 1은 의미 없음
                     FROM HR.EMPLOYEES B
                    WHERE A.DEPARTMENT_ID=B.DEPARTMENT_ID
                      AND B.SALARY>=10000)
     ORDER BY 1;

(IN 연산자,비동등 조인)
    SELECT A.DEPARTMENT_ID AS 부서코드,
           A.DEPARTMENT_NAME AS 부서명
      FROM HR.DEPARTMENTS A
     WHERE A.DEPARTMENT_ID IN(SELECT DISTINCT DEPARTMENT_ID
                                 FROM HR.EMPLOYEES 
                                WHERE SALARY>=10000)
     ORDER BY 1;

(동등 조인)
    SELECT A.DEPARTMENT_ID AS 부서코드,
           A.DEPARTMENT_NAME AS 부서명
      FROM HR.DEPARTMENTS A,(SELECT DISTINCT DEPARTMENT_ID
                                 FROM HR.EMPLOYEES 
                                WHERE SALARY>=10000)B
     WHERE A.DEPARTMENT_ID=B.DEPARTMENT_ID
     ORDER BY 1;

5) NON EQUI JOIN

  - 조인조건에 '=' 이외의 연산자가 사용되는 조인

 

사용예) 사원테이블에서 각 사원이 소속된 부서의 평균급여보다 더 많은 급여를 받는 사원의 사원번호,사원명,부서코드,입사일,급여를 조회하시오.

    SELECT A.EMPLOYEE_ID AS 사원번호,
           A.EMP_NAME AS 사원명,
           A.DEPARTMENT_ID AS 부서코드,
           (SELECT ROUND(AVG(SALARY))
              FROM HR.EMPLOYEES D
             WHERE D.DEPARTMENT_ID=A.DEPARTMENT_ID) AS 부서평균급여,
           A.HIRE_DATE AS 입사일,
           A.SALARY AS 급여
      FROM HR.EMPLOYEES A
     -- 부등호로 비교 >> 비동등 조인
     WHERE A.SALARY > (SELECT C.ASAL
                         FROM (SELECT B.DEPARTMENT_ID,
                                      AVG(B.SALARY) AS ASAL
                                 FROM HR.EMPLOYEES B
                                GROUP BY B.DEPARTMENT_ID)C
                         WHERE A.DEPARTMENT_ID=C.DEPARTMENT_ID)
     ORDER BY 3, 6 DESC;

 

사용예) 회원테이블에서 마일리지가 많은 상위 3명이 2020년 5월 구매한 정보를 조회하시오. Alias는 회원번호,회원명,구매금액 합계

(마일리지가 많은 3명)
  SELECT A.MEM_ID
    FROM (SELECT MEM_ID,MEM_MILEAGE
            FROM MEMBER
           ORDER BY MEM_MILEAGE DESC)A
   WHERE ROWNUM<=3;

:

(2020년 5월 구매한 정보)
  SELECT M.MEM_ID AS 회원번호,
         M.MEM_NAME AS 회원명,
         SUM(C.CART_QTY*PROD_PRICE) AS "구매금액 합계"
    FROM CART C, MEMBER M, PROD P
   WHERE C.CART_NO LIKE '202005%'
     AND C.CART_PROD=P.PROD_ID
     AND M.MEM_ID=C.CART_MEMBER
     AND C.CART_MEMBER = ANY(SELECT A.MEM_ID
                              FROM (SELECT MEM_ID,MEM_MILEAGE
                                      FROM MEMBER
                                     ORDER BY MEM_MILEAGE DESC)A
                              WHERE ROWNUM<=3)
   GROUP BY M.MEM_ID,M.MEM_NAME;

 

2. 외부조인(OUTER JOIN)

  - 내부조인은 조인조건을 만족하는 자료를 대상으로 연산하고 조인조건을 만족하지 않는 자료는 모두 무시함.
  - 외부조인은 자료의 종류가 많은 쪽을 기준으로 부족한 쪽의 테이블에 NULL값의 행을 추가하여 조인 수행

(사용형식:일반 외부조인)
  SELECT 컬럼list
    FROM 테이블1 [별칭1], 테이블2 [별칭2] [, 테이블3 [별칭3],...]
   WHERE 별칭1.컬럼명=별칭2.컬럼명(+) -- 테이블2가 부족한 경우

  - 조인대상 테이블 중 데이터가 부족한 테이블조인조건에 외부조인 연산자 '(+)'를 붙인다.
  - 외부조인 조건이 여러 개인 경우 모두 '(+)'를 붙여야 함.
  - 양쪽 모두 부족한 경우 허용되지 않음
  - 한번에 한 테이블에만 외부조인 할 수 있다.
  - ex) A,B,C 테이블이 외부조인하는 경우 A=B(+) AND C=B(+)는 허용되지 않음
  - (+)연산자는 OR 연산자, IN 연산자와 같이 사용할 수 없음
  - 외부조인조건과 일반조건을 같이 기술하면 외부조인 결과를 얻을 수 없다.
    해결책으로 ANSI 외부조인으로 수행, 또는 서브쿼리를 사용한 외부조인으로 구성

 

(사용형식:ANSI 외부조인)
  SELECT 컬럼list
    FROM 테이블1 [별칭1]
    LEFT|RIGHT|FULL OUTER JOIN 테이블2 [별칭2] ON(조인조건 [AND 일반조건])
                            :
   [WHERE 일반조건]

  - 'LEFT|RIGHT|FULL' : FROM절 쪽의 테이블의 자료가 더 많은 경우 LEFT
                                       FROM절 쪽의 테이블의 자료가 더 적은 경우 RIGHT 
                                       양쪽 모두 부족한 경우 FULL
  - 'WHERE 일반조건' : 모든 테이블에 공통으로 적용될 조건 기술(내부조인 결과로 변형될 위험이 상존)
  - 그 외 특징은 INNER JOIN과 동일

 

사용예) HR계정의 테이블을 이용하여 모든 부서별 사원수와 평균급여를 조회하시오.

(잘못 사용된 예)
  SELECT B.DEPARTMENT_ID AS 부서코드, 
         A.DEPARTMENT_NAME AS 부서명, 
         COUNT(*) AS 사원수, 
         NVL(ROUND(AVG(B.SALARY)),0) AS 평균급여
    FROM HR.DEPARTMENTS A, HR.EMPLOYEES B -- 27개 11개
   WHERE B.DEPARTMENT_ID(+)=A.DEPARTMENT_ID -- 외부조인조건
   GROUP BY B.DEPARTMENT_ID, A.DEPARTMENT_NAME
   ORDER BY 1;

(일반 외부조인)
  SELECT A.DEPARTMENT_ID AS 부서코드, 
         A.DEPARTMENT_NAME AS 부서명, 
         COUNT(B.EMPLOYEE_ID) AS 사원수, 
         NVL(ROUND(AVG(B.SALARY)),0) AS 평균급여
    FROM HR.DEPARTMENTS A, HR.EMPLOYEES B
   WHERE A.DEPARTMENT_ID=B.DEPARTMENT_ID(+)
   GROUP BY A.DEPARTMENT_ID, A.DEPARTMENT_NAME
   ORDER BY 1;

(ANSI 외부조인)
  SELECT A.DEPARTMENT_ID AS 부서코드, 
         A.DEPARTMENT_NAME AS 부서명, 
         COUNT(B.EMPLOYEE_ID) AS 사원수, 
         NVL(ROUND(AVG(B.SALARY)),0) AS 평균급여
    FROM HR.DEPARTMENTS A
    FULL OUTER JOIN HR.EMPLOYEES B ON(A.DEPARTMENT_ID=B.DEPARTMENT_ID) -- 외부조인조건
   GROUP BY A.DEPARTMENT_ID, A.DEPARTMENT_NAME
   ORDER BY 1;

 

사용예) 상품테이블과 분류테이블을 사용하여 모든 분류별 상품의 수를 조회하시오.

  SELECT COUNT(*) FROM LPROD; -- 9개
  SELECT COUNT*DISTINCT PROD_LGU) FROM PROD; -- 6개
(일반 외부조인)
  SELECT A.LPROD_GU AS 분류코드, 
         A.LPROD_NM AS 분류명, 
         COUNT(B.PROD_ID) AS "상품의 수"
    FROM LPROD A, PROD B
   WHERE A.LPROD_GU=B.PROD_LGU(+)
   GROUP BY A.LPROD_GU, A.LPROD_NM
   ORDER BY 1;

(ANSI 외부조인) 
  SELECT A.LPROD_GU AS 분류코드, 
         A.LPROD_NM AS 분류명, 
         COUNT(B.PROD_ID) AS "상품의 수"
    FROM PROD B
   RIGHT OUTER JOIN LPROD A ON(A.LPROD_GU=B.PROD_LGU) 
   GROUP BY A.LPROD_GU, A.LPROD_NM
   ORDER BY 1;

 

사용예) 2020년 4월 모든 상품별 매입집계(수량집계,금액집계)를 조회하시오.

(일반 외부조인)
  SELECT B.PROD_ID AS 상품코드, 
         B.PROD_NAME AS 상품명,
         COUNT(A.BUY_QTY) AS 매입건수,
         NVL(SUM(A.BUY_QTY),0) AS 매입수량합계,
         NVL(SUM(A.BUY_QTY*B.PROD_COST),0) AS 매입금액합계
    FROM BUYPROD A, PROD B
   WHERE A.BUY_PROD(+)=B.PROD_ID
     AND A.BUY_DATE BETWEEN TO_DATE('20200401') AND TO_DATE('20200430')
   GROUP BY B.PROD_ID, B.PROD_NAME 
   ORDER BY 1;

(ANSI 외부조인)
  SELECT B.PROD_ID AS 상품코드, 
         B.PROD_NAME AS 상품명,
         COUNT(A.BUY_QTY) AS 매입건수,
         NVL(SUM(A.BUY_QTY),0) AS 매입수량합계,
         NVL(SUM(A.BUY_QTY*B.PROD_COST),0) AS 매입금액합계
    FROM BUYPROD A
   RIGHT OUTER JOIN PROD B ON(A.BUY_PROD=B.PROD_ID AND
         A.BUY_DATE BETWEEN TO_DATE('20200401') AND TO_DATE('20200430'))
   GROUP BY B.PROD_ID, B.PROD_NAME 
   ORDER BY 1;

(서브쿼리를 이용한 외부조인)
(서브쿼리:2020년 4월 매입집계 : 내부조인)
  SELECT A.BUY_PROD AS BID,
         SUM(A.BUY_QTY) AS SCNT,
         SUM(A.BUY_QTY*B.PROD_COST) AS SAMT
    FROM BUYPROD A, PROD B
   WHERE A.BUY_DATE BETWEEN TO_DATE('20200401') AND TO_DATE('20200430')
     AND A.BUY_PROD=B.PROD_ID
   GROUP BY A.BUY_PROD;

(메인쿼리:모든 상품에 대하여 상품코드,상품명,매입수량합계,매입금액합계)
  SELECT P.PROD_ID AS 상품코드,
         P.PROD_NAME AS 상품명,
         NVL(C.SCNT,0) AS 매입수량합계,
         NVL(C.SAMT,0) AS 매입금액합계
    FROM PROD P, (SELECT A.BUY_PROD AS BID,
                         SUM(A.BUY_QTY) AS SCNT,
                         SUM(A.BUY_QTY*B.PROD_COST) AS SAMT
                    FROM BUYPROD A, PROD B
                   WHERE A.BUY_DATE BETWEEN TO_DATE('20200401') AND TO_DATE('20200430')
                     AND A.BUY_PROD=B.PROD_ID
                   GROUP BY A.BUY_PROD)C
   WHERE P.PROD_ID=C.BID(+)
   ORDER BY 1;

 

사용예) 2020년 4월 모든 상품별 매출집계(수량집계,금액집계)를 조회하시오.

(일반 외부조인)    
  SELECT B.PROD_ID AS 상품코드,
         B.PROD_NAME AS 상품명,
         NVL(SUM(A.CART_QTY),0) AS 매출수량합계,
         NVL(SUM(A.CART_QTY*B.PROD_PRICE),0) AS 매출금액합계
    FROM CART A, PROD B
   WHERE A.CART_PROD(+)=B.PROD_ID
     AND A.CART_NO LIKE '202004%'
   GROUP BY B.PROD_ID, B.PROD_NAME
   ORDER BY 1;

(ANSI 외부조인)
  SELECT B.PROD_ID AS 상품코드,
         B.PROD_NAME AS 상품명,
         NVL(SUM(A.CART_QTY),0) AS 매출수량합계,
         NVL(SUM(A.CART_QTY*B.PROD_PRICE),0) AS 매출금액합계
    FROM CART A
   RIGHT OUTER JOIN PROD B ON(A.CART_PROD=B.PROD_ID AND
         A.CART_NO LIKE '202004%')
   GROUP BY B.PROD_ID, B.PROD_NAME
   ORDER BY 1;

(서브쿼리)
  SELECT B.PROD_ID AS BID,
         SUM(A.CART_QTY) AS SCNT,
         SUM(A.CART_QTY*B.PROD_PRICE) AS SAMT
    FROM CART A, PROD B
   WHERE A.CART_PROD=B.PROD_ID
     AND A.CART_NO LIKE '202004%'
   GROUP BY B.PROD_ID,B.PROD_NAME;

(메인쿼리)
  SELECT P.PROD_ID AS 상품코드,
         P.PROD_NAME AS 상품명,
         NVL(C.SCNT,0) AS 매출수량합계,
         NVL(C.SAMT,0) AS 매출금액합계
    FROM PROD P, (SELECT B.PROD_ID AS BID,
                         SUM(A.CART_QTY) AS SCNT,
                         SUM(A.CART_QTY*B.PROD_PRICE) AS SAMT
                    FROM CART A, PROD B
                   WHERE A.CART_PROD=B.PROD_ID
                     AND A.CART_NO LIKE '202004%'
                   GROUP BY B.PROD_ID,B.PROD_NAME) C
   WHERE P.PROD_ID=C.BID(+)
  ORDER BY 1;

 

문제] 2020년 6월 모든 상품별 매입/매출 집계를 조회하시오.

(ANSI 외부조인)
  SELECT A.PROD_ID AS 상품코드,
         A.PROD_NAME AS 상품명,
         NVL(SUM(B.BUY_QTY),0) AS 매입수량합계,
         NVL(SUM(C.CART_QTY),0) AS 매출수량합계,
         NVL(SUM(B.BUY_QTY*A.PROD_COST),0) AS 매입금액합계,
         NVL(SUM(C.CART_QTY*A.PROD_PRICE),0) AS 매출금액합계
    FROM PROD A
    LEFT OUTER JOIN BUYPROD B ON(A.PROD_ID=B.BUY_PROD AND B.BUY_DATE BETWEEN TO_DATE('20200601') AND TO_DATE('20200630')) 
    LEFT OUTER JOIN CART C ON(A.PROD_ID=C.CART_PROD AND C.CART_NO LIKE '202006%')
   GROUP BY A.PROD_ID, A.PROD_NAME
   ORDER BY 1;

(메인쿼리)
  SELECT P.PROD_ID AS 상품코드,
         P.PROD_NAME AS 상품명,
         NVL(D.SCNT,0) AS 매입수량합계,
         NVL(C.SCNT,0) AS 매출수량합계,
         NVL(D.SAMT,0) AS 매입금액합계,
         NVL(C.SAMT,0) AS 매출금액합계
    FROM PROD P, 
         (SELECT B.PROD_ID AS BID, -- 매출
                 SUM(A.CART_QTY) AS SCNT,
                 SUM(A.CART_QTY*B.PROD_PRICE) AS SAMT
            FROM CART A, PROD B
           WHERE A.CART_PROD=B.PROD_ID
             AND A.CART_NO LIKE '202006%'
           GROUP BY B.PROD_ID,B.PROD_NAME) C, 
         (SELECT A.BUY_PROD AS BID, -- 매입
                 SUM(A.BUY_QTY) AS SCNT,
                 SUM(A.BUY_QTY*B.PROD_COST) AS SAMT
            FROM BUYPROD A, PROD B
           WHERE A.BUY_DATE BETWEEN TO_DATE('20200601') AND TO_DATE('20200630')
             AND A.BUY_PROD=B.PROD_ID
           GROUP BY A.BUY_PROD) D
   WHERE P.PROD_ID=C.BID(+)
     AND P.PROD_ID=D.BID(+)
  ORDER BY 1;

'DBMS' 카테고리의 다른 글

[DBMS/Oracle] 집합 연산자  (0) 2023.03.16
[DBMS/Oracle] 서브쿼리(SUBQUERY)  (1) 2023.03.16
[DBMS/Oracle] ROLLUP과 CUBE함수  (0) 2023.03.15
[DBMS/Oracle] 그룹함수  (0) 2023.03.15
[DBMS/Oracle] 함수  (0) 2023.03.15