방대한 데이터의 세계로, JUST DO DBMS!
두 개 이상의 테이블을 서로 연결하여 데이터를 검색할 때 사용하는 방법으로 두 개의 테이블을 마치 하나의 테이블인 것처럼 보여주는 것을 뜻해요.
JOIN의 기본 사용 방법
- 두 개의 테이블에 하나라도 같은 컬럼이 있어야 해요.
- 두 컬럼의 값은 공유 되어야 해요.
- 보통 조인을 위해서 기본키(Primary Key)와 외래키(Foreign Key)를 활용해요.
SELECT e.EMPLOYEE_ID
, e.FIRST_NAME
, e.DEPARTMENT_ID
, d.DEPARTMENT_ID
, d.DEPARTMENT_NAME
FROM EMPLOYEES e INNER JOIN DEPARTMENTS d
ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
-- ON은 조건절로 e 의 칼럼과 d의 칼럼이 같을 때 라는 뜻이다.
-- WHERE e.EMPLOYEE_ID = 178
-- WHERE e.DEPARTMENT_ID = 270
-- DEPARTMENT_ID가 NULL값인 경우의 데이터는 나오지 않는다.
ORDER BY e.EMPLOYEE_ID
;
SELECT *
FROM EMPLOYEES e
WHERE DEPARTMENT_ID IS NULL;
사원의 FIRST_NAME, LAST_NAME, EMAIL, DEPARTMENT_ID, DEPARTMENT_NAME, JOB_ID, JOB_TITLE, CITY 컬럼을 출력
SELECT e.FIRST_NAME
, e.LAST_NAME
, e.EMAIL
, e.DEPARTMENT_ID
, d.DEPARTMENT_NAME
, j.JOB_ID
, j.JOB_TITLE
, l.CITY
FROM EMPLOYEES e
INNER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
INNER JOIN JOBS j ON e.JOB_ID = j.JOB_ID
INNER JOIN LOCATIONS l ON d.LOCATION_ID = l.LOCATION_ID
WHERE l.CITY = 'Seattle'
ORDER BY e.DEPARTMENT_ID
;
LEFT OUTER JOIN : 왼쪽 테이블이 중심
RIGHT OUTER JOIN : 오른족 테이블이 중심
FULL OUTER JOIN : 양쪽 테이블 모두가 중심
SELECT *
FROM tableA left outer join tableB
SELECT *
FROM tableA right outer join tableB
SELECT *
FROM tableA full outer join tableB
-- left outer join
SELECT e.EMPLOYEE_ID
, e.FIRST_NAME
, e.HIRE_DATE
, jh.EMPLOYEE_ID
, jh.START_DATE
, jh.END_DATE
, jh.JOB_ID
FROM EMPLOYEES e
-- 모든 직원들 중에서 직군을 이동한 잡히스토리에 대한 내용을 알고 싶을 때
LEFT OUTER JOIN JOB_HISTORY jh ON e.EMPLOYEE_ID = jh.EMPLOYEE_ID
-- 직군을 이동한 사람들 중에서 추가적인 내용을 알고 싶을때
-- RIGHT OUTER JOIN JOB_HISTORY jh ON e.EMPLOYEE_ID = jh.EMPLOYEE_ID
-- inner join은 부서이동이 있던 사람에 대한 데이터만
-- INNER JOIN JOB_HISTORY jh ON e.EMPLOYEE_ID = jh.EMPLOYEE_ID
ORDER BY e.EMPLOYEE_ID
;
-- FULL OUTER JOIN
SELECT e.EMPLOYEE_ID
, e.DEPARTMENT_ID
, d.DEPARTMENT_ID
, d.DEPARTMENT_NAME
FROM EMPLOYEES e
-- 양쪽테이블의 모든 테이블을 볼 수 있다.
FULL OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
;
-- 평균 급여보다 적게 받는 사람
-- 평균 급여 : 6,462
SELECT ROUND(AVG(SALARY))
FROM EMPLOYEES e
;
-- WHERE 절에서는 집계함수를 사용할 수 없다.
SELECT EMPLOYEE_ID
, FIRST_NAME
, LAST_NAME
FROM EMPLOYEES e
WHERE SALARY < 6462 -- 평균 급여는 계속 바뀔 수 있다.
-- SALARY < ROUND(AVG(SALARY))
ORDER BY EMPLOYEE_ID
;
-- SUBQUERY
SELECT EMPLOYEE_ID
, FIRST_NAME
, LAST_NAME
FROM EMPLOYEES e
WHERE SALARY < ( SELECT ROUND(AVG(SALARY))
FROM EMPLOYEES e )
ORDER BY EMPLOYEE_ID
;
사원의 이름, 부서번호, 부서명 출력
SELECT e.FIRST_NAME || ' ' || e.LAST_NAME name
, e.DEPARTMENT_ID
, d.DEPARTMENT_NAME
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
;
30번 부서의 사원들의 이름, 직업, 부서명을 출력
SELECT e.FIRST_NAME || ' ' || e.LAST_NAME name
, e.JOB_ID
, d.DEPARTMENT_NAME
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
WHERE e.DEPARTMENT_ID = 30
;
커미션을 받는 사원의 이름, 직업, 부서번호, 부서명을 출력
SELECT e.FIRST_NAME || ' ' || e.LAST_NAME name
, e.JOB_ID
, e.DEPARTMENT_ID
-- , COMMISSION_PCT
, d.DEPARTMENT_NAME
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
WHERE e.COMMISSION_PCT IS NOT NULL
;
지역번호(location_id) 2500번에서 근무하는 사원의 이름, 직업, 부서번호, 부서명을 출력
SELECT e.FIRST_NAME || ' ' || e.LAST_NAME name
, e.JOB_ID
, d.DEPARTMENT_ID
, d.DEPARTMENT_NAME
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
LEFT OUTER JOIN LOCATIONS l ON d.LOCATION_ID = l.LOCATION_ID
WHERE l.LOCATION_ID = 2500
;
이름에 A가 들어가는 사원들의 이름과 부서이름을 출력
SELECT e.FIRST_NAME || ' ' || e.LAST_NAME name
, d.DEPARTMENT_NAME
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
WHERE e.FIRST_NAME LIKE '%A%' OR e.LAST_NAME LIKE '%A%'
;
사원 이름과 그 사원의 관리자 이름(manager)을 출력
SELECT e.FIRST_NAME || ' ' || e.LAST_NAME name -- 사원 이름
, e2.First_name || ' ' || e2.LAST_NAME manager_name -- 매니저이름
FROM EMPLOYEES e
INNER JOIN EMPLOYEES e2 ON e.MANAGER_ID = e2.EMPLOYEE_ID
ORDER BY e2.EMPLOYEE_ID
;
사원 이름과 부서명과 월급을 출력하는데, 월급이 3000이상인 사원을 출력
SELECT e.FIRST_NAME || ' ' || e.LAST_NAME name
, d.DEPARTMENT_NAME
, e.SALARY
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
WHERE e.SALARY >= 3000
ORDER BY e.SALARY
;
급여가 3000에서 5000사이인 사원이 이름과 소속 부서명 출력
SELECT e.FIRST_NAME || ' ' || e.LAST_NAME name
, d.DEPARTMENT_NAME
-- , SALARY
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
WHERE e.SALARY BETWEEN 3000 AND 5000
;
급여가 3000이하인 사원의 이름과 급여, 근무지 출력
SELECT e.FIRST_NAME || ' ' || e.LAST_NAME name
, e.SALARY
-- , l.LOCATION_ID
, l.CITY
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
LEFT OUTER JOIN LOCATIONS l ON d.LOCATION_ID = l.LOCATION_ID
WHERE e.SALARY <= 3000
ORDER BY l.CITY
;
'Steven King'의 부서명을 출력
SELECT --e.FIRST_NAME || ' ' || e.LAST_NAME name ,
d.DEPARTMENT_NAME
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
WHERE e.FIRST_NAME = 'Steven' AND e.LAST_NAME = 'King'
;
IT 부서에서 근무하고 있는 사람을 출력
SELECT e.EMPLOYEE_ID
, e.FIRST_NAME || ' ' || e.LAST_NAME name
, d.DEPARTMENT_NAME
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
WHERE d.DEPARTMENT_NAME = 'IT'
;
employees 테이블에서 사원번호, 이름, 업무, 부서번호, 부서명, 근무지 아이디 출력
SELECT e.EMPLOYEE_ID
, e.FIRST_NAME || ' ' || e.LAST_NAME name
, e.JOB_ID
, e.DEPARTMENT_ID
, d.DEPARTMENT_NAME
, l.LOCATION_ID
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
LEFT OUTER JOIN LOCATIONS l ON d.LOCATION_ID = l.LOCATION_ID
;
'SA_MAN'직군의 사원번호, 이름, 급여, 부서명, 근무지 아이디 출력
SELECT e.EMPLOYEE_ID
, e.FIRST_NAME || ' ' || e.LAST_NAME name
, e.SALARY
, d.DEPARTMENT_NAME
, l.LOCATION_ID
, e.JOB_ID
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
LEFT OUTER JOIN LOCATIONS l ON d.LOCATION_ID = l.LOCATION_ID
WHERE e.JOB_ID = 'SA_MAN'
;
COUNTRY_ID = 'US' 인 LOCATION_ID => 1400, 1500, 1600, 1700 부서테이블에 정보 전체를 조회
SELECT LOCATION_ID
FROM LOCATIONS l
WHERE COUNTRY_ID = 'US'
;
SELECT *
FROM DEPARTMENTS d
WHERE LOCATION_ID IN (1400, 1500, 1600, 1700)
;
SELECT *
FROM DEPARTMENTS d
WHERE LOCATION_ID IN (SELECT LOCATION_ID
FROM LOCATIONS l
WHERE COUNTRY_ID = 'US')
;
월급이 가장 적은 사원의 이름을 FIRST_NAME, LAST_NAME을 연결하여 조회
SELECT MIN(SALARY)
FROM EMPLOYEES e
;
SELECT FIRST_NAME || ' ' || LAST_NAME name
, SALARY
FROM EMPLOYEES e
WHERE SALARY = (SELECT MIN(SALARY)
FROM EMPLOYEES e2 ) -- 서브쿼리의 별칭은 가능한 메인 쿼리와 충돌하지 않게 하는 것이 좋다.
;
월급이 가장 많은 사원
SELECT e.FIRST_NAME || ' ' || LAST_NAME name
, e.SALARY
, j.JOB_TITLE
FROM EMPLOYEES e
LEFT OUTER JOIN JOBS j ON e.JOB_ID = j.JOB_ID
WHERE e.SALARY = (SELECT MAX(SALARY) FROM EMPLOYEES e2)
;
LAST_NAME이 'Kochhar'인 사람의 급여보다 많은 사원의 사원번호, 이름, 담당업무(JOB_ID), JOB_TITLE, 급여를 조회
SELECT e.EMPLOYEE_ID
, e.FIRST_NAME || ' ' || e.LAST_NAME
, e.JOB_ID
, j.JOB_TITLE
-- , e.SALARY
FROM EMPLOYEES e
LEFT OUTER JOIN JOBS j ON e.JOB_ID = j.JOB_ID
WHERE e.SALARY > (SELECT SALARY
FROM EMPLOYEES e2
WHERE LAST_NAME = 'Kochhar' )
;
급여의 평균보다 적은 사원의 사원번호, 이름, 담당업무, 급여, 부서번호, 부서명 출력
SELECT e.EMPLOYEE_ID
, e.FIRST_NAME || ' ' || e.LAST_NAME
, e.JOB_ID
, e.SALARY
, e.DEPARTMENT_ID
, d.DEPARTMENT_NAME
FROM EMPLOYEES e
LEFT OUTER JOIN DEPARTMENTS d ON e.DEPARTMENT_ID = d.DEPARTMENT_ID
WHERE SALARY < (SELECT AVG(SALARY)
FROM EMPLOYEES e2)
;
100번 부서의 최소 급여보다 최소 급여가 많은 다른 모든 부서를 출력
SELECT MIN(SALARY)
FROM EMPLOYEES e2
WHERE DEPARTMENT_ID = 100 -- 6900
;
SELECT DEPARTMENT_ID
, MIN(SALARY)
FROM EMPLOYEES e
GROUP BY DEPARTMENT_ID
HAVING MIN(SALARY) > ( SELECT MIN(SALARY)
FROM EMPLOYEES e2
WHERE DEPARTMENT_ID = 100)
;
업무가 'SA_MAN'인 사원의 이름, 업무(JOB_ID), 부서명, 근무지(CITY)를 출력
SELECT FIRST_NAME
, JOB_ID
, DEPARTMENT_ID
FROM EMPLOYEES e
WHERE JOB_ID = 'SA_MAN'
;
SELECT emp.FIRST_NAME
, emp.JOB_ID
, d.DEPARTMENT_NAME
, l.CITY
FROM ( SELECT FIRST_NAME -- 서브쿼리 자체를 테이블로 사용할 수 있다.
, JOB_ID
, DEPARTMENT_ID
FROM EMPLOYEES e
WHERE JOB_ID = 'SA_MAN') emp
INNER JOIN DEPARTMENTS d ON emp.DEPARTMENT_ID = d.DEPARTMENT_ID
INNER JOIN LOCATIONS l ON d.LOCATION_ID = l.LOCATION_ID
;
가장 많은 사원을 갖는 MANAGER의 사원번호, 관리하는 사원수를 출력
SELECT MAX(COUNT(*))
FROM EMPLOYEES e
GROUP BY MANAGER_ID
SELECT MANAGER_ID
, COUNT(*)
FROM EMPLOYEES e
GROUP BY MANAGER_ID
HAVING COUNT(MANAGER_ID) = ( SELECT MAX(COUNT(*))
FROM EMPLOYEES e
GROUP BY MANAGER_ID )
;
가장 많은 사원이 속해있는 부서 번호와 사원수를 출력
SELECT MAX(COUNT(*))
FROM EMPLOYEES e
GROUP BY DEPARTMENT_ID
;
SELECT DEPARTMENT_ID
, COUNT(EMPLOYEE_ID)
FROM EMPLOYEES e
GROUP BY DEPARTMENT_ID
HAVING COUNT(DEPARTMENT_ID) = ( SELECT MAX(COUNT(*))
FROM EMPLOYEES e
GROUP BY DEPARTMENT_ID )
;
출처
https://media.giphy.com/media/1hVi7JFFzplHW/giphy.gif
https://media.giphy.com/media/jUwpNzg9IcyrK/giphy.gif