[Oracle] SQL문법 3.집합 연산자와 JOIN

작성일     업데이트:

카테고리:

태그:

집합 연산자(SET OPERATOR)

집합 연산자란

  • 여러개의 쿼리문을(=SELECT 결과물) 가지고 하나의 쿼리문으로 만드는 연산자이다
  • 여러개의 SELECT문을 하나로 연결한다
  • 집합 연산자로 결합된 컬럼의 결과 컬럼 또한 데이터타입이 동일해야 한다
  • 양 쿼리문의 결과를 합쳐서 한개의 테이블로 보여줘야 하기 때문에 각 쿼리문의 SELECT절 부분이 같아야 한다
    => 조회할 컬럼이 동일해야 한다


[ UNION ]

SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE = 'D5' -- 6명 조회됨
UNION
SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY > 3000000; -- 8명 조회됨
-- 하지만 중복값이 제거되어 총 14명이 아닌, 6명이 출력된다
  • 합집합
  • 여러개의 쿼리 결과를 합치는 연산자로 중복된 영역은 제외한다
    => 두 쿼리문의 수행 결과를 합친 후 중복값을 한번 제거한다
  • 필수적으로 양쪽 쿼리문을 실행 한 후 합치는 것이기 때문에 성능상 자주 사용하는 것을 권장하지 않는다


[ UNION ALL ]

SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE = 'D5' -- 6명 조회됨
UNION ALL
SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY > 3000000; -- 8명 조회됨
-- 중복값을 제외하지 않아, 둘을 더한 값인 총 14명이 출력된다
  • 합집합 + 교집합
  • 여러 쿼리 결과를 합치는 연산자로 중복된 영역 모두 포함하여 합친다
    => 중복 제거를 하지 않는다


[ INTERSECT ]

SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE = 'D5' -- 6명 조회됨
INTERSECT
SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY > 3000000; -- 8명 조회됨
-- 두 쿼리의 중복되는 부분인 총 2명이 출력된다
  • 교집합
  • 여러 쿼리 결과의 중복된 결과만 추출한다
  • EXISTS 또는 IN 서브쿼리를 이용한 SQL문으로 변경 가능하다


[ MINUS ]

SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE = 'D5' -- 6명 조회됨
MINUS
SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE SALARY > 3000000; -- 8명 조회됨
-- 선행쿼리문에서 후행쿼리문과 중복되는 부분인 2명을 뺀 4명이 출력된다
  • 차집합
  • 선행 쿼리문 결과값에서 후행 쿼리문 결과값을 뺀 나머지 부분을 추출한다
    => 선행 쿼리문 결과값 - 교집합(1회)
  • NOT EXISTS 또는 NOT IN 서브 쿼리를 이용한 SQL문으로 변경 가능하다


JOIN

JOIN이란

  • 두개 이상의 테이블에서 데이터를 함께 조회하고자 할 때 사용되는 구문이다
  • 수행결과는 하나의 결과물(Result Set)으로 나오게 된다
  • 사용 목적
    • 관계형 데이터베이스에서는 중복의 최소화를 위해 최소한의 데이터로 각각의 테이블에 데이터를 보관하고 있다
      => 즉 원하는 데이터 테이블을 새로 만들기보다 JOIN구문을 이용하여 각 테이블간의 관계를 맺고 함께 조회를 하는 것이다
      => 단 무작정 JOIN을 하는 것이 아니라, 일반적으로 테이블의 식별값인 Primary Key와 테이블 간의 연결고리(Foreign Key)에 해당되는 칼럼을 매칭시켜서 조회해야 한다
  • JOIN을 여러번 사용도 가능하다
  • JOIN은 문법상 ORACLE 전용구문과 ANSI구문으로 나누어진다
    => ANSI구문 : American National Standards Institute 미국 표준 협회에서 표준 SQL문을 정립해 놓은 것이다. 표준 SQL문이기 때문에 DBMS의 종류에 제약을 받지 않는다
ORACLE 전용구문 ANSI구문
등가 조인(EQUI JOIN) 내부조인(INNER JOIN) -> JOIN USING/ON
포괄 조인 외부 조인(OUTER JOIN) -> JOIN USING
(LEFT OUTER JOIN) 왼쪽 외부조인(LEFT OUTER JOIN)
(RIGHT OUTER JOIN) 오른쪽 외부조인(RIGHT OUTER JOIN)
  전체 외부 조인(FULL OUTER JOIN) : 오라클에서 사용불가
카테시안곱 교차조인(CROSS JOIN)
자체조인(SELF JOIN)  
비등가조인 (NON EQUI JOIN)  


[ EQUI JOIN(등가) / INNER JOIN(내부) ]

  • 연결시키고자 하는 칼럼 값들이 일치하는 행들만 JOIN해서 조회한다
    => 일치하지 않는 값들은 결과에서 제외한다
  • 가장 일반적으로 사용하는 ‘=’에 의한 JOIN이다
  • 일치하지 않는 값이거나 NULL인 값은 조회되지 않는다


ORACLE (등가조인)
  • [표현법]

    SELECT 조회하고자 하는 컬럼명들,
    FROM 조인하고자 하는 테이블명들
    WHERE 연결할 칼럼에 대한 조건을 제시 (=);
    
    • FROM절에 ‘,’ 로 구분하여 합칠 테이블명들을 나열하고 WHERE절에서 합치기에 사용할 컬럼명을 명시 및 조건을 제시한다
    • WHERE절에서 FROM절에 사용한 테이블 별칭 이용이 가능하다
    • 테이블에서의 별칭은 AS를 쓰지 않고 공백으로만 구분시킨다
    • JOIN시 추가적인 조건을 더 넣고 싶다면 AND로 추가해 주면 된다


  • 예시)

    SELECT EMP_ID, EMP_NAME, DEPT_CODE, DEPT_TITLE
    FROM EMPLOYEE, DEPARTMENT
    WHERE DEPT_CODE = DEPT_ID;
    --EMPLOYEE 테이블의 DEPT_CODE 값과 DEPARTMENT테이블의 DEPT_ID가 일치하는 경우에만 조회된다
    
  • 에러발생 예시)

    SELECT EMP_ID, EMP_NAME, JOB_CODE, JOB_NAME
    FROM EMPLOYEE , JOB
    WHERE JOB_CODE = JOB_CODE;
    -- 에러발생 : column ambiguously defined -> 칼럼명이 애매모호하다
    
    • 연결할 칼럼명이 일치(EMPLOYEE - JOB_CODE/ JOB - JOB_CODE)하는 경우 확실히 어느 테이블의 컬럼인지 제시해주어야 한다
    • 별칭 사용시 : FROM EMPLOYEE E, JOB J 와 같이 테이블의 별칭을 붙이고 WHERE E.JOB_CODE = J.JOB_CODE; 와 같이 컬럼의 출처를 알려주게끔 작성하면 된다
    • 별칭 사용 없을 시 : WHERE EMPLOYEE.JOB_CODE = JOB.JOB_CODE; 와 같이 컬럼명 앞에 테이블명을 붙여주면 된다
    • 별칭을 부여하거나 테이블 명을 그대로 사용하거나 둘중 자유롭게 선택하면 되지만 둘을 혼합해서 사용할 수는 없으니 한쪽으로 통일시켜야 한다


ANSI (내부조인)
  • 연결에 사용하려는 컬럼 명이 같은 경우 USING구문, 다른경우 ON구문을 사용한다
  • 기본적으로 JOIN은 INNER JOIN이며 OUTER JOIN은 반드시 OUTER JOIN을 명시해야한다
  • FROM 절에 기준이 되는 테이블을 하나만 기술한다
  • 이후 JOIN 절에서 함께 조회하고자 하는 테이블과, 매칭시킬 컬럼에 대한 조건도 같이 기술한다
  • JOIN시 추가적인 조건을 더 넣고 싶다면 WHERE절을 추가하여 조건을 제시하면 된다


  • [ON 구문 표현법]

    SELECT 조회할 컬럼명들 나열
    FROM 기준으로 삼을 테이블 1개만 제시
    JOIN 조인할 테이블 1 제시 ON (연결할 칼럼에 대한 조건을 제시(=))
    
    • 연결할 컬럼 명이 다른 경우 무조건 ON구문만 사용 가능하다
  • ON 구문 예시

    SELECT EMP_ID, EMP_NAME, DEPT_CODE, DEPT_TITLE
    FROM EMPLOYEE
    /*INNER*/ JOIN DEPARTMENT ON DEPT_CODE = DEPT_ID;
    -- INNER 는 생략 가능하다
    


  • [USING구문 표현법]

    SELECT 조회하고자 하는 칼럼명들
    FROM 기준으로 삼을 테이블명 1개만 제시
    JOIN 조인할 테이블명 1개만 제시 USING (연결할 컬럼명 1개만 제시)
    
    • 컬럼명이 동일한 경우에만 사용가능하며 동일한 컬럼명 하나만 기술하면 알아서 매칭이 진행된다
    • USING을 사용한 구문에는 컬럼 별칭을 사용할 수 없다
      => only simple column names allowed here 에러 발생
  • USING구문 예시

    SELECT EMP_ID, EMP_NAME, JOB_CODE, JOB_NAME
    FROM EMPLOYEE
    JOIN JOB USING (JOB_CODE);
    -- EMPLOYEE의 JOB_CODE와 JOB의 JOB_CODE를 매칭시킨것임
    


자연조인(NATURAL JOIN)
  • 등가 조인 방법중 하나이기도 하다
    => EQUI JOIN과 비슷하지만 WHERE 조건절 없이 조인한다
  • 동일한 타입과 이름을 가진 칼럼을 조인 조건으로 이용하는 것이다
  • 양 테이블에 일치하는 컬럼명이 단 한개만 존재할 경우 자연조건으로 사용시 알아서 해당 컬럼이 매칭된다
  • 일치하는 컬럼명이 단 하나여야만 하기 때문에 사용하기 까다롭고 잘 사용되지 않는 구문이기도 하다

    SELECT EMP_ID, EMP_NAME, JOB_CODE, JOB_NAME
    FROM EMPLOYEE
    NATURAL JOIN JOB;
    


[ 포괄조인 / OUTER JOIN(외부) ]

  • 테이블간의 JOIN시에 일치하지 않는 행도 포함시켜서 조회가 가능하다
  • 반드시 LEFT / RIGHT를 지정해야한다 ( = 기준이되는 테이블을 지정해야 한다 )

=> 일치하는 행 + 지정한 테이블을 기준으로 일치하지 않는 행도 포함시켜서 조회한다


ORACLE (포괄조인)
  • [표현법]

    SELECT EMP_NAME, SALARY, DEPT_TITLE
    FROM EMPLOYEE, DEPARTMENT
    WHERE DEPT_CODE = DEPT_ID(+);
    
    • 기준으로 삼을 테이블의 반대 컬럼명에 (+)를 붙여준다


ANSI (외부조인)
  • LEFT OUTER JOIN / RIGHT OUTER JOIN

    • 두 테이블중 왼/오른편에 기술된 테이블을 기준으로 JOIN한다
      => 일치하는 것을 찾지 못하더라도 조회하게 된다
  • [표현법]

    SELECT EMP_NAME, SALARY, DEPT_TITLE
    FROM EMPLOYEE LEFT /*OUTER*/ JOIN DEPARTMENT ON DEPT_CODE = DEPT_ID;
    -- OUTER 생략 가능
    
    • LEFT 위치에 LEFT / RIGHT 중 하나를 명시하여 어떤 테이블을 기준으로 삼을 것인지 정한다
  • FULL OUTER JOIN

    SELECT EMP_NAME, SALARY, DEPT_TITLE
    FROM EMPLOYEE FULL /*OUTER*/ JOIN DEPARTMENT ON DEPT_CODE = DEPT_ID;
    
    • LEFT / RIGHT을 명시하는 것 처럼 FULL을 명시하여 사용한다
    • 두 테이블이 가진 모든 행을 조회한다
    • 일치하는 행들 + LEFT OUTER JOIN 기준 새롭게 추가된 행들 + RIGHT OUTER JOIN 전체를 조회한다
    • 자주 사용되는 구문은 아니다
    • ORACLE에서는 사용 불가하다
      => a predicate may reference only one outer-joined table 오류발생


[ 카테시안 곱 / 교차조인(CROSS JOIN) ]

  • Cartesian Product
  • 모든 테이블의 각 행들이 서로서로 매핑된 데이터가 조회된다(= 곱집합)
  • 두 테이블의 행들이 모두 곱해진 행들의 조합이 출력된다
    => 각각 N개 M개의 행을 가진 테이블이 있다면 출력결과로 N*M만큼의 행을 반환하게 된다
    => 모든 경우의 수를 다 따져서 조회를 하는 것 => 방대한 데이터를 출력하게 되므로 과부하의 위험이 있다


ORACLE (카테시안 곱)
  • [표현법]
    SELECT EMP_NAME, DEPT_TITLE
    FROM EMPLOYEE, DEPARTMENT
    -- EMPLOYEE의 모든 행 (23개) * DEPARTMENT의 모든 행 (9개) => 207개 행이 조회됨
    
    • WHERE 조건절에 기술하는 조인문이 잘못되었거나 아예 없을 때 발생하게 된다


ANSI (교차조인)
  • [표현법]
    SELECT EMP_NAME , DEPT_TITLE
    FROM EMPLOYEE
    CROSS JOIN DEPARTMENT
    -- EMPLOYEE의 모든 행 (23개) * DEPARTMENT의 모든 행 (9개) => 207개 행이 조회됨
    
    • CROSS JOIN 을 기술하여 사용한다


[ 자체조인 (SELF JOIN) ]

  • 같은 테이블끼리 조인하는 경우에 사용된다
    => 자기 자신의 테이블과 다시 조인을 맺겠다는 뜻
  • 자체조인의 경우 테이블에 반드시 별칭을 붙여줘야 한다
    => 별칭을 붙이면 서로 다른 테이블인 것처럼 사용이 가능하다


ORACLE (자체조인)
  • [표현법]
    SELECT E.EMP_ID, E.EMP_NAME, E.MANAGER_ID, M.EMP_NAME
    FROM EMPLOYEE E, EMPLOYEE M
    WHERE E.MANAGER_ID = M.EMP_ID(+);
    -- 동일한 EMPLOYEE 테이블을 불러왔지만 각기 다른 별칭으로 사용했다
    


ANSI (자체조인)
  • [표현법]

    SELECT E.EMP_ID, E.EMP_NAME, E.MANAGER_ID, M.EMP_NAME
    FROM EMPLOYEE E
    LEFT JOIN EMPLOYEE M ON E.MANAGER_ID = M.EMP_ID;
    -- 동일한 EMPLOYEE 테이블을 불러왔지만 각기 다른 별칭으로 사용했다
    


[ 비등가조인 (NON EQUI JOIN) ]

  • = 를 사용하지 않는 JOIN문이다
  • 다른 비교연산자 (ex. >, <, <=, >=, BETWEEN A AND B)를 사용하여 JOIN한다
    => 지정한 칼럼값들이 일치하는 경우가 아니라 범위에 포함되는 경우 매칭해서 조회한다
  • =에 비해 효율이 별로 좋지 않아, 가끔 한번씩정도밖에 쓰이지 않는다


ORACLE (비등가조인)
  • [표현법]

    SELECT EMP_NAME, SALARY, SAL_GRADE.SAL_LEVEL
    FROM EMPLOYEE, SAL_GRADE
    WHERE SALARY BETWEEN MIN_SAL AND MAX_SAL;
    


ANSI (비등가조인)
  • [표현법]

    SELECT EMP_NAME, SALARY, SAL_GRADE.SAL_LEVEL
    FROM EMPLOYEE
    JOIN SAL_GRADE ON SALARY BETWEEN MIN_SAL AND MAX_SAL;
    -- USING은 사용불가하다
    


[ 다중 JOIN ]

  • 3개 이상의 테이블들을 조인해서 조회할 때 사용한다
  • 동작 상 조인(연결) 순서가 중요하다
    => 조인의 순서를 제대로 지키지 않을 경우 에러 발생


  • ORACLE (다중조인)
    • [표현법]

      SELECT EMP_ID 사번, EMP_NAME 사원명, DEPT_TITLE 부서명, JOB_NAME 직급명
      FROM EMPLOYEE E , DEPARTMENT D, JOB J
      WHERE E.DEPT_CODE = D.DEPT_ID(+)
          AND E.JOB_CODE = J.JOB_CODE(+);
      


  • ANSI (다중조인)
    • [표현법]

      SELECT EMP_ID 사번, EMP_NAME 사원명, DEPT_TITLE 부서명, JOB_NAME 직급명
      FROM EMPLOYEE E
      LEFT JOIN DEPARTMENT D ON E.DEPT_CODE = D.DEPT_ID
      LEFT JOIN JOB J ON E.JOB_CODE = J.JOB_CODE;
      

댓글남기기