JOIN
* 두개 이상의 테이블에서 데이터를 같이 조회하고자 할 때 사용되는 구문
* 조회결과는 하나의 결과물(Result set)로 나옴
* 관계형 데이터베이스에서는 최소한의 데이터로 각각의 테이블에 데이터를 보관하고 있음.
* 그 이유는, 중복을 최소화하기 위해서 최대한 쪼개서 보관함.
* => 즉, 하나의 테이블에서 모든 데이터를 관리하는 것 보다(중복의 가능성이 존재함)
* => 최대한 테이블 쪼갠 후, JOIN구문을 이용해서 테이블간 "관계"를 맺어 조회하는 것이 효율적
* => 이를 위해, 테이블 간에 "연결고리"에 해당하는 컬럼을 매칭시켜서 조회해야 함.
* JOIN은 크게 "오라클 전용 구문"과 "ANSI(미국국립표준협회) 구문"으로 나뉨.
* => 용어만 다를 뿐, 개념은 똑같음.
SELECT EMP_ID, EMP_NAME, DEPT_CODE
FROM EMPLOYEE;
SELECT DEPT_ID, DEPT_TITLE
FROM DEPARTMENT;
SELECT EMP_ID, EMP_NAME, JOB_CODE
FROM EMPLOYEE;
SELECT JOB_CODE, JOB_NAME
FROM JOB;
ORACLE 구문 VS ANSI구문
오라클 전용 구문 ANSI (오라클, 다른DBMS)구문
등가조인(EQUAL 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)
카테시안 곱(CARTESIAN PRODUCT) 교차 조인(CROSS JOIN)
자체조인(SELF JOIN) JOIN ON 구문을 이용
비등가조인(NON EQUAL JOIN)
등가조인 / 내부조인(INNER JOIN)
* 연결시키는 컬럼의 값이 일치하는 행들만 조인해서 조회
* 일치하지 않는 값들은 조회에서 제외
1. 오라클 전용 구문
SELECT EMP_ID, EMP_NAME, DEPT_CODE, DEPT_TITLE
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE = DEPT_ID;
SELECT EMP_ID, EMP_NAME, JOB.JOB_CODE, JOB_NAME
FROM EMPLOYEE, JOB
WHERE EMPLOYEE.JOB_CODE = JOB.JOB_CODE;
SELECT EMP_ID, EMP_NAME, E.JOB_CODE, J.JOB_CODE, JOB_NAME
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE;
2. ANSI구문
SELECT EMP_ID, EMP_NAME, DEPT_CODE, DEPT_TITLE
FROM EMPLOYEE
JOIN DEPARTMENT
ON (DEPT_CODE = DEPT_ID);
SELECT EMP_ID, EMP_NAME, EMPLOYEE.JOB_CODE, JOB_NAME
FROM EMPLOYEE
JOIN JOB
ON (EMPLOYEE .JOB_CODE = JOB .JOB_CODE);
SELECT EMP_ID, EMP_NAME, JOB_CODE, JOB_NAME
FROM EMPLOYEE
JOIN JOB
USING (JOB_CODE);
SELECT EMP_ID, EMP_NAME, JOB_CODE, JOB_NAME
FROM EMPLOYEE
NATURAL JOIN JOB;
SELECT EMP_ID, EMP_NAME, SALARY, JOB_NAME
FROM EMPLOYEE, JOB
WHERE EMPLOYEE.JOB_CODE = JOB.JOB_CODE
AND JOB_NAME ='대리';
SELECT EMP_ID, EMP_NAME, SALARY, JOB_NAME
FROM EMPLOYEE E
JOIN JOB J ON (E.JOB_CODE = J.JOB_CODE)
WHERE JOB_NAME='대리';
실습문제
SELECT *
FROM DEPARTMENT;
SELECT EMP_NAME, DEPT_CODE
FROM EMPLOYEE;
SELECT EMP_ID, EMP_NAME, BONUS
FROM EMPLOYEE, DEPARTMENT
WHERE EMPLOYEE.DEPT_CODE = DEPARTMENT.DEPT_ID
AND DEPT_TITLE = '인사관리부';
SELECT EMP_ID, EMP_NAME, BONUS
FROM EMPLOYEE
JOIN DEPARTMENT ON (EMPLOYEE.DEPT_CODE = DEPARTMENT.DEPT_ID)
WHERE DEPT_TITLE = '인사관리부';
SELECT *
FROM DEPARTMENT;
SELECT EMP_NAME, DEPT_CODE
FROM EMPLOYEE;
SELECT EMP_NAME, SALARY, HIRE_DATE
FROM EMPLOYEE, DEPARTMENT
WHERE EMPLOYEE.DEPT_CODE = DEPARTMENT.DEPT_ID
AND DEPARTMENT.DEPT_TITLE != '총무부';
SELECT EMP_NAME, SALARY, HIRE_DATE
FROM EMPLOYEE
JOIN DEPARTMENT ON EMPLOYEE.DEPT_CODE = DEPARTMENT.DEPT_ID
WHERE DEPARTMENT.DEPT_TITLE != '총무부';
SELECT EMP_NAME, BONUS
FROM EMPLOYEE;
SELECT DEPT_CODE
FROM EMPLOYEE;
SELECT EMP_ID, EMP_NAME, BONUS, DEPT_TITLE
FROM EMPLOYEE, DEPARTMENT
WHERE EMPLOYEE.DEPT_CODE = DEPARTMENT.DEPT_ID
AND EMPLOYEE.BONUS IS NOT NULL;
SELECT EMP_ID, EMP_NAME, BONUS, DEPT_TITLE
FROM EMPLOYEE
JOIN DEPARTMENT ON(EMPLOYEE.DEPT_CODE = DEPARTMENT.DEPT_ID)
WHERE EMPLOYEE.BONUS IS NOT NULL;
SELECT *
FROM DEPARTMENT;
SELECT *
FROM LOCATION;
SELECT DEPT_ID, DEPT_TITLE, LOCAL_CODE, LOCAL_NAME
FROM DEPARTMENT, LOCATION
WHERE DEPARTMENT.LOCATION_ID = LOCATION.LOCAL_CODE;
SELECT DEPT_ID, DEPT_TITLE, LOCAL_CODE, LOCAL_NAME
FROM DEPARTMENT
JOIN LOCATION ON(DEPARTMENT.LOCATION_ID = LOCATION.LOCAL_CODE);
포괄조인 / 외부조인(OUTER JOIN)
* 테이블간의 JOIN시 일치하지 않는 행들도 포함시켜서 조회 가능
* 단, LEFT/RIGHT를 지정해야 함(기준이 LEFT/ RIGHT인지를 지정하라는 뜻)
SELECT EMP_NAME, SALARY, DEPT_TITLE
FROM EMPLOYEE
JOIN DEPARTMENT ON(DEPT_CODE = DEPT_ID);
SELECT EMP_NAME, SALARY, DEPT_TITLE
FROM EMPLOYEE LEFT OUTER JOIN DEPARTMENT
ON (DEPT_CODE = DEPT_ID);
SELECT EMP_NAME, SALARY, DEPT_TITLE
FROM EMPLOYEE, DEPARTMENT
WHERE EMPLOYEE.DEPT_CODE = DEPARTMENT.DEPT_ID(+);
SELECT EMP_NAME, SALARY,DEPT_ID, DEPT_TITLE
FROM EMPLOYEE RIGHT OUTER JOIN DEPARTMENT
ON (DEPT_CODE = DEPT_ID);
SELECT EMP_NAME, SALARY, DEPT_ID, DEPT_TITLE
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE(+) = DEPT_ID;
SELECT EMP_NAME, SALARY, DEPT_ID, DEPT_TITLE
FROM EMPLOYEE
FULL OUTER JOIN DEPARTMENT ON(DEPT_CODE = DEPT_ID);
카테시안곱 / 교차조인(CROSS JOIN)
* 카테시안 곱(CARTESIAN PRODUCT)
* 모든 테이블의 각 행들이 서로 맵핑된 결과가 조회됨(모든 경우의 수를 다 찍겠다. 곱집합)
* 두 테이블의 행들이 모두 곱해진 행들의 조합이 다 출력( 방대함, 과부하)
* 예) EMPLOYEE 테이블의 총 23개의 행 / DEPARTMENT 테이블 총 9개의 행
* 23 * 7 = 207개의 행이 결과로 나옴
SELECT EMP_NAME, DEPT_TITLE
FROM EMPLOYEE, DEPARTMENT;
SELECT EMP_NAME, DEPT_TITLE
FROM EMPLOYEE
CROSS JOIN DEPARTMENT;
비등가조인(NON EQUAL JOIN)
* '='(등호, 동등비교연산자)이 없는 경우
* 등호를 사용하지 않는 JOIN
* 지정한 컬럼값이 일치하는 경우가 아니라, "범위"에 포함되는 경우는 모두 조회함.
SELECT *
FROM EMPLOYEE;
SELECT *
FROM SAL_GRADE;
SELECT EMP_NAME, SALARY, SAL_GRADE.SAL_LEVEL, MIN_SAL, MAX_SAL
FROM EMPLOYEE, SAL_GRADE
WHERE SALARY BETWEEN MIN_SAL AND MAX_SAL;
SELECT EMP_NAME, SALARY, SAL_GRADE.SAL_LEVEL, MIN_SAL, MAX_SAL
FROM EMPLOYEE
JOIN SAL_GRADE ON (SALARY BETWEEN MIN_SAL AND MAX_SAL);
자체조인(SELF JOIN)
* 같은 테이블끼리 다시 한번 조인하는 경우
* 즉, 자기자신의 테이블과 다시 조인을 하는 경우
SELECT EMP_ID "사번", EMP_NAME "사원명", SALARY "급여", MANAGER_ID "사수의 사번"
FROM EMPLOYEE;
SELECT * FROM EMPLOYEE E;
SELECT * FROM EMPLOYEE M;
SELECT E.EMP_ID "사원의 사번", E.EMP_NAME "사원의 사원명", E.DEPT_CODE "사원의 부서코드", E.SALARY "사원의 급여",
M.EMP_ID "사수의 사번", M.EMP_NAME "사수의 사원명", M.DEPT_CODE "사수의 부서코드", M.SALARY "사수의 급여"
FROM EMPLOYEE E, EMPLOYEE M
WHERE E.MANAGER_ID = M.EMP_ID(+);
SELECT E.EMP_ID "사원의 사번", E.EMP_NAME "사원의 사원명", E.DEPT_CODE "사원의 부서코드", E.SALARY "사원의 급여",
M.EMP_ID "사수의 사번", M.EMP_NAME "사수의 사원명", M.DEPT_CODE "사수의 부서코드", M.SALARY "사수의 급여"
FROM EMPLOYEE E
LEFT JOIN EMPLOYEE M ON (E.MANAGER_ID = M.EMP_ID);
SELECT E.EMP_ID "사원의 사번", E.EMP_NAME "사원의 사원명", E.DEPT_CODE "사원의 부서코드",D1.DEPT_TITLE "사원의 부서명", E.SALARY "사원의 급여",
M.EMP_ID "사수의 사번", M.EMP_NAME "사수의 사원명", M.DEPT_CODE "사수의 부서코드",D2.DEPT_TITLE "사수의 부서명", M.SALARY "사수의 급여"
FROM EMPLOYEE E
LEFT JOIN EMPLOYEE M ON(E.MANAGER_ID = M.EMP_ID)
LEFT JOIN DEPARTMENT D1 ON(E.DEPT_CODE = D1.DEPT_ID)
LEFT JOIN DEPARTMENT D2 ON(M.DEPT_CODE = D2.DEPT_ID);
다중조인
* 3개 이상의 테이블을 조인
SELECT * FROM EMPLOYEE;
SELECT * FROM DEPARTMENT;
SELECT * FROM JOB;
SELECT * FROM LOCATION;
SELECT EMP_ID "사번", EMP_NAME "사원명", DEPT_TITLE "부서명", JOB_NAME "직급명", LOCAL_NAME "근무지역명"
FROM EMPLOYEE E, DEPARTMENT D, JOB J, LOCATION L
WHERE E.DEPT_CODE = D.DEPT_ID(+)
AND E.JOB_CODE = J.JOB_CODE
AND D.LOCATION_ID = L.LOCAL_CODE(+);
SELECT EMP_ID "사번", EMP_NAME "사원명", DEPT_TITLE "부서명", JOB_NAME "직급명", LOCAL_NAME "근무지역명"
FROM EMPLOYEE E
LEFT JOIN DEPARTMENT D ON(E.DEPT_CODE = D.DEPT_ID)
JOIN JOB J ON(E.JOB_CODE = J.JOB_CODE)
LEFT JOIN LOCATION L ON(D.LOCATION_ID = L.LOCAL_CODE);
SELECT * FROM EMPLOYEE;
SELECT * FROM DEPARTMENT;
SELECT * FROM JOB;
SELECT * FROM LOCATION;
SELECT * FROM NATIONAL;
SELECT * FROM SAL_GRADE;
SELECT
E.EMP_ID "사번",
E.EMP_NAME "사원",
D.DEPT_TITLE "부서명",
J.JOB_NAME "직급명",
L.LOCAL_NAME "근무지역명",
N.NATIONAL_NAME "근무국가명",
S.SAL_LEVEL "급여등급"
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)
LEFT JOIN LOCATION L ON(D.LOCATION_ID = L.LOCAL_CODE)
LEFT JOIN NATIONAL N ON(L.NATIONAL_CODE = N.NATIONAL_CODE)
JOIN SAL_GRADE S ON(E.SALARY BETWEEN S.MIN_SAL AND S.MAX_SAL);