[Oracle] 04_DML(SELECT)_JOIN

2022. 8. 25. 17:33·📗 self-study/📗 KH정보교육원 당산지원

04_DML(SELECT)_JOIN

 

<JOIN>
    
    두 개 이상의 테이블에서 데이터를 같이 조회하고자 할 때 사용되는 구문
    조회 결과는 하나의 결과물(RESULT SET)로 나옴
    
    관계형 데이터베이스에서는 최소한의 데이터로 각각의 테이블에 데이터를 보관하고 있음
    (중복을 최소화하기 위해서 최대한 쪼개서 관리함)
    => 즉, JOIN 구문을 이용해 여러 개의 테이블과의 관계를 맺어 같이 조회해야 함
    => 단, 무작정 JOIN 구문을 작성해서 조회를 하는 게 아니라
         테이블간의 "연결고리"에 해당하는 컬럼 (== 외래키)를 매칭시켜서 JOIN 해 줘야 함
         
         JOIN은 크게 "오라클 전용구문"과 "ANSI(미국국립표준협회) 구문" 으로 나뉨

오라클 전용 구문 ANSI 구문
등가조인 내부조인(INNER JOIN) -> JOIN USING / ON
(EQUAL JOIN) 외부조인(OUTER JOIN) -> 실제로 이렇게 쓰지는 않고 개념적인 내용
=> 연결고리 컬럼에 해당하는 값들이 "같은 것들만" 가지고 오겠다 (등가조인, "내부"조인)
=> 연결고리 컬럼에 해당하는 값들이 "일치하지 않아도" 가지고 오겠다 (등가조인, "외부"조인)
포괄조인 왼쪽 외부조인(LEFT OUTER JOIN) 
(LEFT OUTER) 오른쪽 외부조인(RIGHT OUTER JOIN)
  전체 외부조인(FULL OUTER JOIN) -> 오라클에서는 불가
 
카테시안 곱(CARTESIAN PRODUCT) 교차조인(CROSS JOIN)
=> 모든 경우의 수에 대해 모두 곱하겠다
자체조인(SELF JOIN)  
 비등가조인(NON EQUAL JOIN)  
-- 전체 사원들의 사번, 사원명, 부서코드, 부서명까지 알아내고자 한다면?
SELECT EMP_ID, EMP_NAME, DEPT_CODE -- 부서명을 알 수 없음
FROM EMPLOYEE; -- EMPLOYEE 테이블의 DEPT_CODE 컬럼이 부서 정보를 담고 있음

SELECT DEPT_ID, DEPT_TITLE -- 사번, 사원명을 알 수 없음
FROM DEPARTMENT; -- DEPARTMENT 테이블의 DEPT_ID 컬럼

-- 전체 사원들의 사번, 사원명, 직급코드, 직급명까지 알아내고자 한다면?
SELECT EMP_ID, EMP_NAME, JOB_CODE
FROM EMPLOYEE; -- EMPLOYEE 테이블의 JOB_CODE  컬럼
 
SELECT JOB_CODE, JOB_NAME
FROM JOB; -- JOB 테이블의 JOB_CODE 컬럼

--> 조인을 통해서 연결고리에 해당하는 컬럼만 제대로 매칭시킨다면 마치 하나의 결과물로 조회 가능

 


    1. 등가조인(EQUAL JOIN) / 내부조인(INNER JOIN)
    연결시키려는 컬럼의 값들이 일치하는 행들만 조인돼서 조회
    (== 일치하지 않는 값들은 조회에서 제외됨)


-->> 오라클 전용 구문
-- FROM절에 조회하고자 하는 테이블들을 콤마(,)로 나열
-- WHERE절에 매칭시킬 컬럼명(연결고리)에 대한 조건을 제시함

-- 전체 사원들의 사번, 사원명, 부서코드, 부서명 같이 조회
-- 1) 연결할 두 컬럼명이 다른 경우 (EMPLOYEE 테이블의 DEPT_CODE / DEPARTMENT 테이블의 DEPT_ID)
SELECT EMP_ID, EMP_NAME, DEPT_CODE, DEPT_TITLE
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE = DEPT_ID;
--> 일치하지 않는 값은 조회에서 제외된 것 확인 가능
-- (DEPT_CODE가 NULL이었던 2명의 데이터는 조회가 안 됨, DEPARTMENT 테이블의 DEPT_ID 컬럼에는 NULL이 존재하지 않음)
-- (DEPT_ID가 D3, D4, D7인 부서의 부서명이 조회가 안 됨! EMPLOYEE 테이블의 DEPT_CODE 컬럼에는 D3, D4, D7이 존재하지 않음)

-- 전체 사원들의 사번, 사원명, 직급코드, 직급명 같이 조회
-- 2) 연결할 두 컬럼명이 같은 경우 (EMPLOYEE 테이블의 JOB_CODE / JOB 테이블의 JOB_CODE)
/*
SELECT EMP_ID, EMP_NAME, 
FROM EMPLOYEE, JOB
WHERE JOB_CODE = JOB_CODE;
*/
--- 에러 (AMBIGUOUSLY: 애매하다, 모호하다 => 확실히 어떤 테이블의 어느 컬럼인지를 명시해야 함)

-- 해결방법 1) 테이블명을 직접 명시하여 이용하는 방법 (테이블명.컬럼명)
SELECT EMP_ID, EMP_NAME, EMPLOYEE.JOB_CODE, JOB.JOB_CODE, JOB_NAME
FROM EMPLOYEE, JOB
WHERE EMPLOYEE.JOB_CODE = JOB.JOB_CODE;

-- 해결방법 2) 테이블에 별칭을 붙여서 별칭을 이용하는 방법 (별칭.컬럼명) -> 각 테이블마다 별칭 부여 가능
SELECT EMP_ID, EMP_NAME, E.JOB_CODE, J.JOB_NAME
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE;

 

-->> ANSI 구문
-- FROM절에 기준이 될 테이블명 하나만 명시한 뒤
-- 그 뒤에 JOIN절에서 같이 조회하고자 하는 테이블명을 기술! 또한 매칭시킬 컬럼에 대한 조건도 같이 기술 (USING / ON 구문)

-- 사번, 사원명, 부서코드, 부서명 조회
-- 1) 연결할 두 컬럼명이 다른 경우 (EMPLOYEE 테이블의 DEPT_CODE / DEPARTMENT 테이블의 DEPT_ID)
-- => 무조건 ON 구문만 가능함 (USING 구문은 불가능)
SELECT EMP_ID, EMP_NAME, DEPT_CODE, DEPT_TITLE
FROM EMPLOYEE
/* INNER */ JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID);
--> INNER는 생략 가능

-- 사번, 사원명, 직급코드, 직급명 조회
-- 2) 연결할 두 컬럼명이 같은 경우(EMPLOYEE 테이블의 JOB_CODE / JOB테이블의 JOB_CODE)
-- => ON 구문, USING 구문 둘 다 사용 가능
-- 2_1) ON 구문 이용:  AMBIGUOUSLY 오류가 발생할 수 있기 때문에 확실히 명시해야 함(테이블명, 별칭)
SELECT EMP_ID, EMP_NAME, E.JOB_CODE, JOB_NAME
FROM EMPLOYEE E
JOIN JOB J ON (E. JOB_CODE = J.JOB_CODE);

-- 2_2) USING 구문 이용: AMBIGUOUSLY 오류 발생 X
-- 동일한 컬럼명 하나만 잘 적어 주면알아서 매칭시켜 줌
SELECT EMP_ID, EMP_NAME, JOB_CODE, JOB_NAME
FROM EMPLOYEE
JOIN JOB USING (JOB_CODE);

-- [참고] 위의 예시는 NATURAL JOIN (자연조인)으로도 가능
SELECT EMP_ID, EMP_NAME, JOB_CODE, JOB_NAME
FROM EMPLOYEE
NATURAL JOIN JOB;
-- 두 개의 테이블만 제시한 상태,
-- 마침 운 좋게도 두 개의 테이블에 일치하는 컬럼이 유일하게 한 개씩 존재(JOB_CODE)
-- => 알아서 매칭되어 조회됨

-- 추가적인 조건도 제시 가능
-- 직급이 대리인 사원들의 정보 조회 (사번, 사원명, 급여, 직급명)

-->> 오라클 전용 구문
SELECT EMP_ID, EMP_NAME, SALARY, JOB_NAME
FROM EMPLOYEE E, JOB J
WHERE E.JOB_CODE = J.JOB_CODE; -- 연결고리에 대한 조건
    AND JOB_NAME = '대리' -- 추가적인 조건
-- 협업 시 가독성을 높이기 위해 보통 조건은 한 줄씩 띄어쓰기, 들여쓰기 해서 쓴다.

-->> ANSI구문
SELECT EMP_ID, EMP_NAME, SALARY, JOB_NAME
FROM EMPLOYEE E
-- JOIN JOB USING (JOB_CODE);
JOIN JOB J ON (E.JOB_CODE = J.JOB_CODE)
    WHERE JOB_NAME = '대리';
----- 실습문제 -----
-- 1. 부서가 '인사관리부'인 사원들의 사번, 사원명, 보너스를 조회

-->> 오라클 전용 구문
SELECT EMP_ID, EMP_NAME, BONUS
FROM EMPLOYEE E, DEPARTMENT D
WHERE E.DEPT_CODE = D.DEPT_ID
    AND DEPT_TITLE = '인사관리부';

-->> ANSI 구문
SELECT EMP_ID, EMP_NAME, BONUS
FROM EMPLOYEE
JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID)
    WHERE DEPT_TITLE = '인사관리부';

-- 2. 부서가 '총무부'가 아닌 사원들의 사원명, 급여, 입사일을 조회

-->> 오라클 전용 구문
SELECT EMP_NAME, SALARY, HIRE_DATE
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE = DEPT_ID
    AND DEPT_TITLE != '총무부';

-->> ANSI 구문
SELECT EMP_NAME, SALARY, HIRE_DATE
FROM EMPLOYEE 
JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID)
    WHERE DEPT_TITLE != '총무부';

-- 3. 보너스를 받는 사원들의 사번, 사원명, 보너스, 부서명 조회

-->> 오라클 전용 구문
SELECT EMP_ID, EMP_NAME, BONUS, D.DEPT_TITLE
FROM EMPLOYEE E, DEPARTMENT D
WHERE E.DEPT_CODE = D.DEPT_ID
 AND BONUS IS NOT NULL;

-->> ANSI 구문
SELECT EMP_ID, EMP_NAME, BONUS, DEPT_TITLE
FROM EMPLOYEE
JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID)
    WHERE BONUS IS NOT NULL;

-- 4. 아래의 두 테이블을 참고하여 부서코드, 부서명, 지역코드, 지역명 (LOCAL_NAME) 조회
SELECT * FROM DEPARTMENT -- LOCATION_ID
SELECT * FROM LOCATION -- LOCAL_CODE

-->> 오라클 전용 구문
SELECT DEPT_ID, DEPT_TITLE, LOCATION_ID, LOCAL_NAME
FROM DEPARTMENT, LOCATION
WHERE LOCATION_ID = LOCAL_CODE;

-->> ANSI 구문
SELECT DEPT_ID, DEPT_TITLE, D.LOCATION_ID, L.LOCAL_NAME
FROM DEPARTMENT D
JOIN LOCATION L ON (D.LOCATION_ID = L.LOCAL_CODE);

   

 2. 포괄조인 / 왼쪽, 오른쪽, 전체 외부조인(OUTER JOIN)
    테이블간의 JOIN 시 일치하지 않은 행도 포함시켜서 조회 가능
    단, 반드시 LEFT/RIGHT 중 기준 테이블을 지정해야 함
    
    => 일단 일치하는 것들 조회 + 기준 테이블에서 누락됐던 것들 조회

 

-- "전체" 사원들의 사원명, 급여, 부서명 조회
SELECT EMP_NAME, SALARY, DEPT_TITLE
FROM EMPLOYEE
JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID);
-- DEPT_CODE가 NULL인 두 명의 사원 정보가 조회되지 않음
-- 부서에 배정된 사원이 없는 부서(D3, D4, D7) 에 대한 부서명(마케팅부, 국내영업부, 해외영업3부)도 조회되지 않음
-- => 기본적으로 등가조인 / 내부조인에서는 일치하는 것들만 조회를 하기 때문에 위의 두 항목들이 조회되지 않음

-- 1) LEFT OUTER JOIN: 두 테이블 중 왼편에 기술된 테이블을 기준으로 JOIN
--                              즉, 뭐가 되었든 간에 왼편에 기술된 테이블의 데이터는 무조건 한 번씩은 조회하게 됨
--                              (일치하는 것을 찾지 못하더라도)

-->> ANSI 구문
SELECT EMP_NAME, SALARY, DEPT_TITLE
FROM EMPLOYEE -- "기준점이 될 왼편 테이블" 기술
LEFT /* OUTER */ JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID);
-- INNER JOIN 했을 때는 부서가 NULL값인 2명의 정보는 나오지 않았지만
-- OUTER JOIN으로 연결하니까 NULL값이 채워져서 2명이 추가로 나옴!
--> EMPLOYEE 테이블을 기준으로 조회했기 때문에 EMPLOYEE에 존재하는 데이터는 뭐가 되었든 간에 조회되게끔 하겠음

--> 오라클 전용 구문
SELECT EMP_NAME, SALARY, DEPT_TITLE
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE = DEPT_ID(+);
--> 내가 기준으로 삼을 테이블의 컬럼명이 아닌 반대 테이블의 컬럼명에 (+) 기호를 붙여 줌

-- 2) RIGHT OUTER JOIN: 두 테이블 중 오른편에 기술된 테이블을 기준으로 JOIN
--                                 즉, 뭐가 되었든 간에 오른편에 기술된 테이블의 데이터는 무조건 한 번씩 조회하게 됨
--                                  (일치하는 것을 찾지 못하더라도)

--> ANSI구문
SELECT EMP_NAME, SALARY, DEPT_TITLE
FROM EMPLOYEE 
RIGHT /* OUTER */ JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID);

-- LEFT와 RIGHT는 "방향 차이"이므로 위, 아래의 OUTER JOIN은 완벽하게 똑같음!

SELECT EMP_NAME, SALARY, DEPT_TITLE
FROM DEPARTMENT
LEFT JOIN EMPLOYEE ON (DEPT_CODE = DEPT_ID);

--> 오라클 전용 구문
SELECT EMP_NAME, SALARY, DEPT_TITLE
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE(+) = DEPT_ID;

-- LEFT / RIGHT OUTER JOIN의 결과는 일단 등가조인의 결과로 공통적인 것들을 한 번씩 다 조회한 후
-- 기준이 되는 테이블에서 누락된 정보가 추가적으로 조회되는 개념

-- 3) FULL OUTER JOIN: 두 테이블이 가진 모든 행을 조회할 수 있도록 JOIN
--                               (단, 오라클 전용 구문에서는 불가)
-->> ANSI구문
SELECT EMP_NAME, SALARY, DEPT_TITLE
FROM EMPLOYEE
FULL /* OUTER */ JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID);
--> 일치하는 내용물들 조회 + 왼쪽 테이블에서 누락된 것 조회 + 오른쪽 테이블에서 누락된 것 조회

--> 오라클 전용 구문 (에러: only one outer-joined table)
SELECT EMP_NAME, SALARY, DEPT_TITLE
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE(+) = DEPT_ID(+);

 

    3. 카테시안 곱 (CATESIAN PRODUCT) / 교차조인 (CROSS JOIN)
    모든 테이블의 각 행들이 서로서로 맵핑된 결과가 조회됨(곱집합)
    두 테이블의 행들이 모두 곱해진 행들의 조합이 모두 다 출력됨 => 방대한 데이터 출력 => 과부하의 위험
    
    => 조인 조건이 잘못되었거나 누락됐을 경우 발생하기 때문에 주의해야 함
    
    예) 각각 N개, M개 행을 가진 테이블의 카테시안 곱 결과물은 N * M 개의 행이 나옴

-- 사원명, 부서명 조회
--> 오라클 전용 구문
SELECT EMP_NAME, DEPT_TITLE
FROM EMPLOYEE, DEPARTMENT; --> 23행 * 9행 => 207개 행 조회

--> ANSI구문
SELECT EMP_NAME, DEPT_TITLE
FROM EMPLOYEE
CROSS JOIN DEPARTMENT;

 

    4. 비등가 조인(NON EQUAL JOIN)
    '=' (동등비교연산자) 를 사용하지 않는 조인문
    지정한 컬럼값이 일치하는 경우가 아닌 "범위"에 포함되는 경우 매칭시켜서 조회하겠다는 뜻

-- 사원명, 급여, 급여등급(EMPLOYEE)
SELECT EMP_NAME, SALARY, SAL_LEVEL
FROM EMPLOYEE;

-- EMPLOYEE 테이블에 SAL_LEVEL이 없다는 가정하에 SAL_GRADE 테이블에서 가져온다고 해 보자!

-- SAL_GRADE 조회
SELECT *
FROM SAL_GRADE;

-- 사원명, 급여, 급여등급(SAL_GRADE)
--> 오라클 전용 구문
SELECT EMP_NAME, SALARY, S.SAL_LEVEL
FROM EMPLOYEE E, SAL_GRADE S
-- WHERE SALARY >= MIN_SAL AND SALARY <= MAX_SAL; -- 연결고리에 대한 조건
WHERE SALARY BETWEEN MIN_SAL AND MAX_SAL; -- 연결고리에 대한 조건

--> ANSI 구문
SELECT EMP_NAME, SALARY, S.SAL_LEVEL
FROM EMPLOYEE E
JOIN SAL_GRADE S ON (SALARY BETWEEN MIN_SAL AND MAX_SAL);
--> 등가조인일 경우 INNER가 기본 타입
--> 조건을 걸면 자동으로 비등가조인 됨

 

   5. 자체 조인(SELF JOIN)
    
    같은 테이블을 다시 한번 조인하는 경우
    즉, 자기 자신의 테이블과 다시 조인을 맺는 경우

-- 사원의 사번, 사원명, 사원 급여, 사수의 사번
SELECT EMP_ID "사원의 사번"
         , EMP_NAME "사원명"
         , SALARY "사원 급여"
         , MANAGE_ID "사수의 사번"
FROM EMPLOYEE;

-- 사원의 사번, 사원명, 사원의 부서코드, 사원의 급여
-- 사원의 사번, 사원명, 사수의 부서코드, 사수의 급여

-- 사원정보, 사수정보를 각각 도출해 낼 테이블의 별칭
SELECT * FROM EMPLOYEE E; -- 사원에 대한 정보 도출용 테이블: E => 연결고리 컬럼: MANAGER_ID
SELECT * FROM EMPLOYEE M; -- 사수에 대한 정보 도출용 테이블: 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, EMPLOYEE M
-- WHERE E.MANAGER_ID = M.EMP_ID; -- 일치하는 등가조인에 대한 조건을 제시했을 때: 사수가 있는 경우 (NULL이 아닐 경우)만 조회
WHERE E.MANAGER_ID = M.EMP_ID(+); -- 사수가 없는 사원도 모두 조회하고 싶을 때
-- 기준을 사원으로 잡고 기준이 아닌 곳에 (+)를 걸어 주면 사수가 NULL값인 값도 모두 조회됨

--> ANSI 구문
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
-- JOIN EMPLOYEE M ON (E.MANAGER_ID = M.EMP_ID); -- 내부조인 구문으로 작성했을 경우: 사수가 있는 경우만 조회
LEFT JOIN EMPLOYEE M ON (E.MANAGER_ID = M.EMP_ID); -- 외부조인 구문으로 작성했을 경우: 사수가 없는 경우도 포함해서 조회

 

   <다중 JOIN>
    3개 이상의 테이블을 조인하는 것

-- 사번, 사원명, 부서명, 직급명
SELECT * FROM EMPLOYEE;        --    DEPT_CODE     JOB_CODE
SELECT * FROM DEPARTMENT;   --     DEPT_ID
SELECT * FROM JOB;                 --                          JOB_CODE

--> 오라클 전용 구문
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, JOB_NAME
FROM EMPLOYEE E, DEPARTMENT D, JOB J
-- WHERE DEPT_CODE = DEPT_ID -- 등가조인 조건을 부여할 경우: 부서 배치가 안 된 사원들은 조회 안 됨
WHERE DEPT_CODE = DEPT_ID(+) -- 포괄조인 조건을 부여할 경우: 부서 배치가 안 된 사원들을 포함해서 조회
    AND E.JOB_CODE = J.JOB_CODE;

--> ANSI 구문
SELECT EMP_ID, EMP_NAME, DEPT_TITLE, JOB_NAME
FROM EMPLOYEE
-- JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID) -- DEPARTMENT 테이블을 내부 조인 한 경우: 부서 배치가 안 된 사원들은 조회 안 됨
LEFT JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID) -- EMPLOYEE 기준 LEFT OUTER JOIN 된 상태
                                                                            -- DEPARTMENT 테이블을 LEFT OUTER JOINT 한 경우: 부서배치가 안 된 사원들을 포함해서 조회
       JOIN JOB USING (JOB_CODE); -- EMPLOYEE 기준 INNER JOIN 된 상태
-- 컬럼명 일치할 때
-- ON 구문: 별칭 필수, USING 구문: 별칭 필수 아님

-- 사번, 사원명, 부서명, 직급명, 근무지역명 (LOCAL_NAME)
SELECT * FROM EMPLOYEE;     --  DEPT_CODE      JOB_CODE
SELECT * FROM DEPARTMENT --  DEPT_ID                                    LOCATION_ID
SELECT * FROM JOB;              --                        JOB_CODE
SELECT * FROM LOCATION;    --                                                  LOCAL_CODE 

--> 오라클 전용 구문
SELECT EMP_ID "사번"
         , EMP_NAME "사원명"
         , DEPT_TITLE "부서명"
         , JOB_NAME "직급명"
         , LOCAL_NAME "근무지역명"
FROM EMPLOYEE E, DEPARTMENT D, JOB J, LOCATION
WHERE DEPT_CODE = DEPT_ID
    AND E.JOB_CODE = J.JOB_CODE
    AND LOCATION_ID = LOCAL_CODE;
    
--> ANSI 구문
SELECT EMP_ID "사번"
         , EMP_NAME "사원명"
         , DEPT_TITLE "부서명"
         , JOB_NAME "직급명"
         , LOCAL_NAME "근무지역명"
FROM EMPLOYEE
JOIN DEPARTMENT ON (DEPT_CODE = DEPT_ID)
JOIN JOB USING (JOB_CODE)
JOIN LOCATION ON (LOCATION_ID = LOCAL_CODE); -- 사실상 DEPARTMENT 테이블에 JOIN하는 개념)
-- 주의사항! 다중 JOIN 시, ANSI 구문을 이용할 경우 테이블명을 기술하는 순서가 중요!
-- LOCATION 테이블이 DEPARTMENT 테이블보다 먼저 조인되면 EMPLOYEE 테이블에 조인되는 꼴이기 때문에
-- EMPLOYEE 테이블에 LOCATION_ID 컬럼이 없어서 오류 발생

-- 사원명, 부서명, 직급명, 근무지역명, 근무국가명, 급여등급(SAL_GRADE)
SELECT * FROM EMPLOYEE;      -- DEPT_CODE     JOB_CODE           SALARY
SELECT * FROM DEPARTMENT; --   DEPT_ID                                                            LOCATION_ID
SELECT * FROM LOCATION;     --                                                                          LOCAL_CODE        NATIONAL_CODE
SELECT * FROM JOB;               --                      JOB_CODE
SELECT * FROM SAL_GRADE;    --                                          MIN_SAL, MAX_SAL
SELECT * FROM NATIONAL;     --                                                                                                    NATIONAL_CODE

--->> 오라클 전용 구문
SELECT EMP_NAME "사원명"
         , DEPT_TITLE "부서명"
         , JOB_NAME "직급명"
         , LOCAL_NAME "근무지역명"
         , NATIONAL_NAME "근무국가명"
         , S.SAL_LEVEL "급여등급"
FROM EMPLOYEE E, DEPARTMENT , JOB J, SAL_GRADE S, LOCATION L, NATIONAL N
WHERE DEPT_CODE = DEPT_ID
  AND E.JOB_CODE = J.JOB_CODE
  AND SALARY BETWEEN MIN_SAL AND MAX_SAL
  AND LOCATION_ID = LOCAL_CODE
  AND L.NATIONAL_CODE = N.NATIONAL_CODE;                                                                                                                                                                                                                                                                                                                    
    --> 주의사항: 다중 조인 할 테이블이 많아질 경우 최대한 헷갈리지 않게 그냥 별칭 붙이자!
    
--> ANSI 구문
SELECT EMP_NAME "사원명"
     , DEPT_TITLE "부서명"
     , JOB_NAME "직급명"
     , LOCAL_NAME "근무지역명"
     , NATIONAL_NAME "근무국가명"
     , S.SAL_LEVEL "급여등급"
FROM EMPLOYEE E
JOIN DEPARTMENT D ON (E.DEPT_CODE = D.DEPT_ID)
JOIN JOB J USING (JOB_CODE)
JOIN SAL_GRADE S ON (E.SALARY BETWEEN S.MIN_SAL AND S.MAX_SAL)
JOIN LOCATION L ON (D.LOCATION_ID = L.LOCAL_CODE)
JOIN NATIONAL N ON (L.NATIONAL_CODE = N.NATIONAL_CODE); -- USING도 가능

-- 사원 사번, 사원명, 사원의 부서명, 사원 급여
-- 사수 사번, 사수명, 사수의 부서명, 사수 급여
SELECT * FROM EMPLOYEE E; -- 사원 테이블로부터 MANAGER_ID 컬럼        DEPT_CODE
SELECT * FROM EMPLOYEE M; -- 사수 테이블로부터 EMP_ID 컬럼               DEPT_CODE
SELECT * FROM DEPARTMENT; --                                                           DEPT_ID

--> 오라클 전용 구문
SELECT E.EMP_ID "사원의 사번"
         , E.EMP_NAME "사원의 이름"
         , D1.DEPT_TITLE "사원의 부서명" -- E.DEPT_CODE "사원 부서코드"
         , E.SALARY "사원의 급여"
         , M.EMP_ID "사수의 사번"
         , M.EMP_NAME "사수의 이름"
         , D2.DEPT_TITLE "사수의 부서명" -- M.DEPT_CODE "사수 부서코드"
         , M.SALARY "사수의 급여"
FROM EMPLOYEE E, EMPLOYEE M, DEPARTMENT D1, DEPARTMENT D2
WHERE (E.MANAGER_ID = M.EMP_ID)
  AND (E.DEPT_CODE = D1.DEPT_ID)
  AND (M.DEPT_CODE = D2.DEPT_ID);

--> ANSI 구문
SELECT E.EMP_ID "사원의 사번"
         , E.EMP_NAME "사원의 이름"
         , D1.DEPT_TITLE "사원의 부서명" -- E.DEPT_CODE "사원 부서코드"
         , E.SALARY "사원의 급여"
         , M.EMP_ID "사수의 사번"
         , M.EMP_NAME "사수의 이름"
         , D2.DEPT_TITLE "사수의 부서명" -- M.DEPT_CODE "사수 부서코드"
         , M.SALARY "사수의 급여"
FROM EMPLOYEE E
JOIN EMPLOYEE M ON (E.MANAGER_ID = M.EMP_ID)
JOIN DEPARTMENT D1 ON (E.DEPT_CODE = D1.DEPT_ID)
JOIN DEPARTMENT D2 ON (M.DEPT_CODE = D2.DEPT_ID);

 

----- JOIN 종합 실습문제 -----

-- 1. 직급이 대리이면서 ASIA 지역에 근무하는 직원들의 사번, 사원명, 직급명, 부서명, 근무지역명, 급여를 조회하시오
-->> 오라클 전용 구문
SELECT E.EMP_ID "사번"
         , E.EMP_NAME "사원명"
         , J.JOB_NAME "직급명"
         , D.DEPT_TITLE "부서명"
         , L.LOCAL_NAME "근무지역명"
         , E.SALARY "급여"
FROM EMPLOYEE E, DEPARTMENT D, JOB J, LOCATION L
WHERE E.JOB_CODE = J.JOB_CODE
    AND E.DEPT_CODE = D.DEPT_ID
    AND D.LOCATION_ID = L.LOCAL_CODE
    AND J.JOB_NAME = '대리'
    AND L.LOCAL_NAME LIKE 'ASIA%';
    
-->> ANSI 구문
SELECT E.EMP_ID "사번"
         , E.EMP_NAME "사원명"
         , J.JOB_NAME "직급명"
         , D.DEPT_TITLE "부서명"
         , L.LOCAL_NAME "근무지역명"
         , E.SALARY "급여"
FROM EMPLOYEE E
JOIN DEPARTMENT D ON (E.DEPT_CODE = D.DEPT_ID)
JOIN JOB J ON (E.JOB_CODE = J.JOB_CODE)
JOIN LOCATION L ON (D.LOCATION_ID = L.LOCAL_CODE)
    WHERE J.JOB_NAME = '대리'
    AND L.LOCAL_NAME LIKE 'ASIA%';

-- 2. 70년대생이면서 여자이고, 성이 전씨인 직원들의 사원명, 주민번호, 부서명, 직급명을 조회하시오
-->> 오라클 전용 구문
SELECT E.EMP_NAME "사원명"
         , E.EMP_NO "주민번호"
         , D.DEPT_TITLE "부서명" -- D.DEPT_ID = E.DEPT_CODE
         , J.JOB_CODE "직급명" -- E.JOB_CODE = J.JOB_CODE
FROM EMPLOYEE E, DEPARTMENT D, JOB J
WHERE E.DEPT_CODE =D.DEPT_ID
    AND E.JOB_CODE = J.JOB_CODE
    AND TO_NUMBER(SUBSTR(E.EMP_NO, 1, 2), 99) BETWEEN 70 AND 79
    AND SUBSTR(E.EMP_NO, 8, 1) IN ('2', '4')
    AND E.EMP_NAME LIKE '전%';
    
-->> ANSI 구문
SELECT E.EMP_NAME "사원명"
         , E.EMP_NO "주민번호"
         , D.DEPT_TITLE "부서명" -- D.DEPT_ID = E.DEPT_CODE
         , J.JOB_CODE "직급명" -- E.JOB_CODE = J.JOB_CODE
FROM EMPLOYEE E
JOIN DEPARTMENT D ON (D.DEPT_ID = E.DEPT_CODE)
JOIN JOB J ON (J.JOB_CODE = E.JOB_CODE)
WHERE TO_NUMBER(SUBSTR(E.EMP_NO, 1, 2), 99) BETWEEN 70 AND 79
    AND SUBSTR(E.EMP_NO, 8, 1) IN ('2', '4')
    AND E.EMP_NAME LIKE '전%';

-- 3. 이름에 '형'자가 들어있는 직원들의 사번, 사원명, 직급명을 조회하시오
-->> 오라클 전용 구문
SELECT E.EMP_ID "사번"
         , E.EMP_NAME "사원명"
         , J.JOB_NAME "직급명" -- J.JOB_CODE = E.JOB_CODE
FROM EMPLOYEE E, JOB J
WHERE J.JOB_CODE = E.JOB_CODE
    AND E.EMP_NAME LIKE '%형%';

-->> ANSI 구문
SELECT E.EMP_ID "사번"
         , E.EMP_NAME "사원명"
         , J.JOB_NAME "직급명" -- J.JOB_CODE = E.JOB_CODE
FROM EMPLOYEE E
JOIN JOB J ON (J.JOB_CODE = E.JOB_CODE)
    WHERE E.EMP_NAME LIKE '%형%';

-- 4. 해외영업팀에 근무하는 직원들의 사원명, 직급명, 부서코드, 부서명을 조회하시오
-->> 오라클 전용 구문
SELECT E.EMP_NAME "사원명"
         , J.JOB_NAME "직급명"
         , D.DEPT_ID "부서코드"
         , D.DEPT_TITLE "부서명" -- J.JOB_CODE = E.JOB_CODE / D.DEPT_ID = E.DEPT_CODE
FROM EMPLOYEE E, JOB J, DEPARTMENT D
WHERE J.JOB_CODE = E.JOB_CODE
    AND D.DEPT_ID = E.DEPT_CODE
    AND D.DEPT_TITLE LIKE '해외영업%'
-->> ANSI 구문
SELECT E.EMP_NAME "사원명"
         , J.JOB_NAME "직급명"
         , D.DEPT_ID "부서코드"
         , D.DEPT_TITLE "부서명" -- J.JOB_CODE = E.JOB_CODE / D.DEPT_ID = E.DEPT_CODE
FROM EMPLOYEE E
JOIN JOB J ON (J.JOB_CODE = E.JOB_CODE)
JOIN DEPARTMENT D ON (D.DEPT_ID = E.DEPT_CODE)
    WHERE D.DEPT_TITLE LIKE '해외영업%'

-- 5. 보너스를 받는 직원들의 사원명, 보너스, 연봉, 부서명, 근무지역명을 조회하시오
-->> 오라클 전용 구문
 SELECT E.EMP_NAME "사원명"
          , E.BONUS "보너스"
          , E.SALARY * 12 "연봉"
          , D.DEPT_TITLE "부서명" -- D.DEPT_ID = E.DEPT_CODE
          , L.LOCAL_NAME "근무지역명" -- L.LOCAL_CODE = D.LOCATION_ID
FROM EMPLOYEE E, DEPARTMENT D, LOCATION L
WHERE D.DEPT_ID(+) = E.DEPT_CODE
-- (+): 붙이는 곳은 기준 반대! = 기준 테이블의 null 값도 포함해서 계산해 주라
    AND L.LOCAL_CODE(+) = D.LOCATION_ID
    AND E.BONUS IS NOT NULL;
-->> ANSI 구문
 SELECT E.EMP_NAME "사원명"
          , E.BONUS "보너스"
          , E.SALARY * 12 "연봉"
          , D.DEPT_TITLE "부서명" -- D.DEPT_ID = E.DEPT_CODE
          , L.LOCAL_NAME "근무지역명" -- L.LOCAL_CODE = D.LOCATION_ID
FROM EMPLOYEE E
LEFT JOIN DEPARTMENT D ON (E.DEPT_CODE =D.DEPT_ID)
LEFT JOIN LOCATION L ON (L.LOCAL_CODE = D.LOCATION_ID)
WHERE E.BONUS IS NOT NULL;


-- 6. 부서가 있는 직원들의 사원명, 직급명, 부서명, 근무지역명을 조회하시오
-->> 오라클 전용 구문
SELECT E.EMP_NAME "사원명"
         , J.JOB_NAME "직급명" -- J.JOB_CODE = E.JOB_CODE
         , D.DEPT_TITLE "부서명" -- D.DEPT_ID = E.DEPT_CODE
         , L.LOCAL_NAME "근무지역명" --  L.LOCAL_CODE = D.LOCATION_ID
FROM EMPLOYEE E, JOB J, DEPARTMENT D, LOCATION L
WHERE J.JOB_CODE = E.JOB_CODE
    AND D.DEPT_ID = E.DEPT_CODE
    AND L.LOCAL_CODE = D.LOCATION_ID
    AND E.DEPT_CODE IS NOT NULL;
         -->> ANSI 구문
SELECT E.EMP_NAME "사원명"
         , J.JOB_NAME "직급명" -- J.JOB_CODE = E.JOB_CODE
         , D.DEPT_TITLE "부서명" -- D.DEPT_ID = E.DEPT_CODE
         , L.LOCAL_NAME "근무지역명" --  L.LOCAL_CODE = D.LOCATION_ID
FROM EMPLOYEE E
JOIN JOB J ON (J.JOB_CODE = E.JOB_CODE)
JOIN DEPARTMENT D ON (D.DEPT_ID = E.DEPT_CODE)
JOIN LOCATION L ON (L.LOCAL_CODE = D.LOCATION_ID)
    WHERE E.DEPT_CODE IS NOT NULL;

-- 7. '한국' 과 '일본' 에 근무하는 직원들의 사원명, 부서명, 근무지역명, 근무국가명을 조회하시오
-->> 오라클 전용 구문
SELECT E.EMP_NAME "사원명"
         , D.DEPT_TITLE "부서명" -- D.DEPT_ID = E.DEPT_CODE
         , L.LOCAL_NAME "근무지역명" -- L.LOCAL_CODE = D.LOCATION_ID
         , N.NATIONAL_NAME "근무국가명" -- N.NATIONAL_CODE = L.NATIONAL_CODE
FROM EMPLOYEE E, DEPARTMENT D, LOCATION L, NATIONAL N
WHERE D.DEPT_ID = E.DEPT_CODE
    AND L.LOCAL_CODE = D.LOCATION_ID
    AND N.NATIONAL_CODE = L.NATIONAL_CODE
    AND N.NATIONAL_NAME IN ('한국', '일본');
-->> ANSI 구문
SELECT E.EMP_NAME "사원명"
         , D.DEPT_TITLE "부서명" -- D.DEPT_ID = E.DEPT_CODE
         , L.LOCAL_NAME "근무지역명" -- L.LOCAL_CODE = D.LOCATION_ID
         , N.NATIONAL_NAME "근무국가명" -- N.NATIONAL_CODE = L.NATIONAL_CODE
FROM EMPLOYEE E
JOIN DEPARTMENT D ON (D.DEPT_ID = E.DEPT_CODE)
JOIN LOCATION L ON (L.LOCAL_CODE = D.LOCATION_ID)
JOIN NATIONAL N ON (N.NATIONAL_CODE = L.NATIONAL_CODE)
    WHERE N.NATIONAL_NAME IN ('한국', '일본');

-- 8. 보너스를 받지 않는 직원들 중 직급코드가 J4 또는 J7 인 직원들의 사원명, 직급명, 급여를 조회하시오
-->> 오라클 전용 구문
SELECT E.EMP_NAME "사원명"
         , J.JOB_NAME "직급명" -- J.JOB_CODE = E.JOB_CODE
         , E.SALARY "급여"
FROM EMPLOYEE E, JOB J
WHERE J.JOB_CODE = E.JOB_CODE
    AND BONUS IS NULL
    AND E.JOB_CODE IN ('J4', 'J7');
-->> ANSI 구문
SELECT EMP_NAME "사원명"
         , JOB_NAME "직급명" -- J.JOB_CODE = E.JOB_CODE
         , SALARY "급여"
FROM EMPLOYEE E
JOIN JOB USING (JOB_CODE)
    WHERE BONUS IS NULL
        AND JOB_CODE IN ('J4', 'J7');

-- 9. 사번, 사원명, 직급명, 급여등급 (SAL_GRADE), 구분을 조회하는데
-- 이 때, 구분에 해당하는 값은
-- 급여등급이 S1, S2 인 경우 '고급'
-- 급여등급이 S3, S4 인 경우 '중급'
-- 급여등급이 S5, S6 인 경우 '초급' 으로 조회되게 하시오
-->> 오라클 전용 구문
SELECT E.EMP_ID "사번"
         , J.JOB_NAME "직급명" -- J.JOB_CODE = E.JOB_CODE
         , DECODE(S.SAL_LEVEL, 'S1', '고급', 'S2', '고급', 'S3', '중급', 'S4', '중급', 'S5', '초급',  '초급') -- S.SAL_LEVEL = E.SAL_LEVEL
FROM EMPLOYEE E, JOB J, SAL_GRADE S
WHERE J.JOB_CODE = E.JOB_CODE
    AND S.SAL_LEVEL = E.SAL_LEVEL;
-->> ANSI 구문
SELECT EMP_ID "사번"
         , JOB_NAME "직급명" -- J.JOB_CODE = E.JOB_CODE
         , DECODE(SAL_LEVEL, 'S1', '고급', 'S2', '고급', 'S3', '중급', 'S4', '중급', 'S5', '초급',  '초급') -- S.SAL_LEVEL = E.SAL_LEVEL
FROM EMPLOYEE
JOIN JOB USING (JOB_CODE)
JOIN SAL_GRADE USING (SAL_LEVEL)

-- 10. 각 부서별 총 급여합을 조회하되 이 때, 총 급여합이 1000만원 이상인 부서명, 급여합을 조회하시오
-->> 오라클 전용 구문
SELECT D.DEPT_TITLE "부서명"
        , SUM(E.SALARY) "급여합"
FROM EMPLOYEE E, DEPARTMENT D
WHERE D.DEPT_ID = E.DEPT_CODE
GROUP BY D.DEPT_TITLE
    HAVING SUM(E.SALARY) >= 10000000;
-->> ANSI 구문
SELECT D.DEPT_TITLE "부서명"
        , SUM(E.SALARY) "급여합"
FROM EMPLOYEE E
JOIN DEPARTMENT D ON (D.DEPT_ID = E.DEPT_CODE)
GROUP BY D.DEPT_TITLE
    HAVING SUM(E.SALARY) >= 10000000;

-- 11. 각 부서별 평균급여를 조회하여 부서명, 평균급여 (정수처리) 로 조회하시오 단, 부서배치가 안된 사원들의 평균도 같이 나오게끔 하시오
-->> 오라클 전용 구문
SELECT DEPT_TITLE "부서명"
         , ROUND(AVG(SALARY),0) "평균급여"
FROM EMPLOYEE, DEPARTMENT
WHERE DEPT_CODE = DEPT_ID(+)
GROUP BY DEPT_CODE, DEPT_TITLE(+);

-->> ANSI 구문
SELECT DEPT_TITLE "부서명"
         , ROUND(AVG(SALARY),0) "평균급여"
FROM EMPLOYEE
LEFT JOIN DEPARTMENT ON (DEPT_CODE =DEPT_ID)
GROUP BY DEPT_CODE, DEPT_TITLE;
저작자표시 (새창열림)
'📗 self-study/📗 KH정보교육원 당산지원' 카테고리의 다른 글
  • [Oracle] 06_DDL(CREATE)_DDL계정
  • [Oracle] 05_DML(SELECT)_SUBQUERY
  • [Oracle] 03_DML(SELECT)_GROUP BY
  • [Oracle] 02_DML(SELECT)_함수(Function)
천재강쥐
천재강쥐
  • 천재강쥐
    디버거도 버거다
    천재강쥐
  • 전체
    오늘
    어제
    • Category (467)
      • 진짜 너무 궁금한데 이걸 나만 몰라...? (0)
      • 💾 Portfolio (2)
      • 🐤 CodingTest (28)
        • Java (20)
        • ᕕ(ꐦ°᷄д°᷅)ᕗ❌ (5)
      • 🚀 from error to study (142)
        • AI (1)
        • Cloud (2)
        • DB (12)
        • Front-End (16)
        • Github (14)
        • Java (39)
        • Mac (7)
        • Normal (29)
        • Server (22)
      • 📘 certificate (44)
        • 📘 리눅스마스터1급 (1)
        • 📘⭕️ 정보처리기사 (40)
        • 📘⭕️ SQLD (3)
      • 📗 self-study (234)
        • 📗 inflearn (35)
        • 📗 생활코딩 (8)
        • 📗 KH정보교육원 당산지원 (190)
      • 🎨 Scoop the others (0)
        • 📖 Peeking into other people.. (0)
        • 🇫🇷 (0)
        • 📘⭕️ 한국사능력검정시험 심화 (11)
        • 오블완 (4)
  • 인기 글

  • hELLO· Designed By정상우.v4.10.1
천재강쥐
[Oracle] 04_DML(SELECT)_JOIN
상단으로

티스토리툴바