본문으로 바로가기

서브쿼리

category 데이터베이스/MySQL 2019. 1. 9. 23:56

서브 쿼리

 

서브 쿼리란 SQL 문장 안에서 보조로 사용되는 또 다른 SELECT 문입니다.

 

최종 결과 출력 쿼리를 메인 쿼리이면 이를 보조하는 SELECT문이 바로 서브 쿼리 입니다.

 

서브 쿼리는 SELECT , FROM , WHERE절 모두 사용 가능하고

 

또한 INSERT UPDATE MERGE DELETE 문에서 사용 가능합니다.

메인 쿼리와의 연관성에 따라

-연관성 없는 서브 쿼리

-연관성 있는 서브 쿼리

 

형태에 따라

-일반 서브 쿼리(SELECT 절)

-인라인 뷰(FROM 절)

-중첩 쿼리(WHERE 절)

 

우선 연관성 없는 서브 쿼리에 대해 알아 봅시다.

 

연관성 없는 서브 쿼리는 메인 쿼리와의 연관성이 없는 서브 쿼리입니다.

 

즉 메인 테이블과 조인 조건이 걸리지 않습니다.

 

SELECT count(*)

FROM employees

WHERE salary>=(SELECT AVG(salary)

FROM employees);

 

이 쿼리는 전 사원 평균 급여 이상 받는 사원 수를 조회합니다.

 

메인 쿼리와 연관성 자체가 없습니다. 단일행 을 반환

 

SELECT count(*)

FROM employees

WHERE department_id IN ( SELECT department_id

FROM departments

WHERE parent_id IS NULL);

 

 

이 쿼리는 부서 테이블에 parent_id 가 널인 부서번호를 가진 사원 총 건수를 반환합니다.

 

마찬가지로 메인 테이블과 서브 쿼리는 연관성이 없습니다. 여러 행을 반환

 

SELECT employee_id, emp_name, job_id

FROM employees

WHERE (employee_id , job_id) IN (SELECT employee_id , job_id

FROM job_history);

 

job_history 테이블에 있는 employee_id job_id 와 같은 건을 사원 테이블에서 찾는 쿼리입니다.

 

마찬가지로 연관성 또한 없습니다. 동시에 2개 이상 컬럼 값이 같은 건을 찾고 있다는 점이 특징입니다.

 

또한 UPDATE, DELETE에서도 쓰일 수 있습니다.

 

UPDATE employees

SET salary=( SELECT AVG(salary)

FROM employees);

 

위 쿼리는 전 사원 급여를 평균 금액으로 업데이트 하는 겁니다.

 

DELETE employees

WHERE salary >= (SELECT AVG(salary)

FROM employees);

 

 

위 쿼리는 평균 급여보다 많이 받는 사원을 제거합니다.

 

 

이렇게 연관성이 없는 서브 쿼리에 대해 봤습니다.

 

두 번째로 연관성이 있는 서브 쿼리에 대해서 알아봅시다.

 

 

연관성이 있는 서브 쿼리란 메인 테이블과 조인 조건이 걸린 서브 쿼리를 말합니다.

 

SELECT a.department_id , a.department_name

FROM departments a

WHERE EXISTS( SELECT 1

FROM job_history b

WHERE a.department_id =b.department_id);

 

서브 쿼리 안에서 메인 쿼리에서 사용 된 테이블의 부서번호와 job_history의 부서번호 가 같은 건을 조회합니다.

 

EXISTS연산과 함께 서브쿼리 내 조인 조건이 포함돼있음을 나타냅니다.

 

따라서 이 쿼리는 job_history에 있는 부서만 조회가 되겠죠 ???

 

왜냐하면 해당 서브쿼리에서 테이블 기준으로 같은 것을 조회하여 출력하기 때문입니다.

 

SELECT a.employee_id,

(SELECT b.emp_name

FROM employees b

WHERE a.employee_id=b.employee_id) AS emp_name,

a.department_id,

(SELECT b.department_name

FROM department b

WHERE a.department_id=b.department_id) AS dep_name

FROM job_history a;

 

 

이 쿼리는 job_history를 조회하고 있습니다.

 

뽑는 값을 SELECT 서브쿼리로 구하게 됩니다. 왜냐하면 job_history로는 사원 이름 부서 이

 

름을 뽑지 못합니다.

 

첫 번째 서브 쿼리에서 사원 이름을 뽑는데 이는 사원 테이블과 job_hisotry 테이블의 id를

 

조인하여 사원 테이블에 있는 사원 이름을 출력 해주게 됩니다. 두 번째 서브 쿼리도 마찬 가지 입니다.

 

이렇게 SELECT 절에도 서브 쿼리를 넣을 수 있습니다.

 

또다른 쿼리를 봅시다.

 

SELECT a.department_id, a.department_name

FROM department a

WHERE EXISTS ( SELECT 1

FROM employees b

WHERE a.department_id=b.department_id

AND b.salary > (SELECT AVG(salary)

FROM employees)

  );

 

이 쿼리는 우선 사원 테이블에서 평균 급여를초과하는 사원을 걸러내고(연관성이 없는 서브쿼

 

리) 평균 급여초과를 받는 사원이 속한 부서가 존재하는(연관성이 있는 서브쿼리) 부서의 이

 

름과 id를 추출합니다.

 

연관성 있는 서브 쿼리 역시 UPDATE DELETE에서도 사용 가능합니다.

 

여러 응용을 살펴봅시다.

 

우선 부서 테이블 상위 부서 번호가 90에 속하는 사원들의 부서별 평균 급여를 조회 해봅시다.

 

SELECT department_id, AVG(salary)

FROM employees a

WHERE department_id IN ( SELECT department_id

FROM departments

 WHERE parent_id = 90)

GROUP BY department_id;

 

연관성 없는 쿼리로 우선 부서테이블에서 상위 부서 번호가 90인 부서 번호를 뽑아서 사원 테

 

이블에 있는 부서별 사원 급여 평균(AVG(salary)를 구합니다.

 

이 결과를 이용하여 상위 부서 90에 속하는 모든 사원 급여를 자신의 부서별 평균급여로 갱신

 

해 봅시다.

 

UPDATE employees a

SET a.salary = ( SELECT sal

FROM ( SELECT b.department_id, AVG(c.salary) as sal

FROM departments b

employees c

WHERE b.parent_id=90

AND b.department_id=c.department_id

GROUP BY b.department_id) d

WHERE a.department_id = d.department_id)

WHERE a.department_id IN (SELECT department_id

FROM departments

WHERE parent_id =90 ) ;

 

많이 어려워 보일 수도 있습니다. 하지만 각각 조각으로 나눠서 본다면 쉽습니다.

 

우선 큰 틀(빨간 부분 ) 을 보면 employees 테이블의 급여를 상위 부서 90인 사원들을 조건

 

으로 하여 갱신 합니다.

 

갱신할 값인 a.salary는 무엇이냐면 sal 값인데 이 값은 SELECT를 한 테이블(파란색 코드) 로부터의 평균 급여 입니다.

 

즉 이 SELECT 테이블은 우선 부서와 사원 테이블로 부터 상위 부서 90번이고 해당 부서에 속

 

하는 사원의 부서를 조건으로 하는 테이블 d입니다.

 

이 d에서 AVG(c.salary) 값을 통해 갱신 한다는 거죠.

 

이 테이블 d의 SELECT 조건(초록 부분 WHERE 절)으로는 마찬가지로 업데이트 시킬 사원 테

 

이블의 부서번호와 SELECT한 테이블의 부서번호(즉 갱신 할 부서) 같다는 조건이 들어갑니

 

다. 즉 상위 부서 90

 

이고 자기 부서의 각 사원들에 대해 평균 급여를 구하여 이를 sal을 통해 a.salary에 넣는

 

다는 것입니다.

 

이렇게 굉장히 복잡해 보이지만 나중가면 더욱 복잡한 쿼리문들이 있을겁니다.

 

빙산의 일각이라 생각하고 하나하나 차근차근 공부해보는 것도 괜찮은 것 같습니다.

 

 

 

 

 

'데이터베이스 > MySQL' 카테고리의 다른 글

MySQL 함수들(3)  (0) 2019.01.02
MySQL 함수들(2)  (0) 2019.01.01
MySQL 함수들(1)  (0) 2018.12.29
MySQL 데이터베이스  (0) 2018.12.28
MySQL 저장 프로시저  (0) 2018.12.27