Oracle

[Oracle] 서브쿼리

eunnys 2024. 2. 13. 11:38

*** 서브쿼리 (Sub Query)

- 쿼리 문장 안에 다른 쿼리가 포함된 것

- 서브쿼리, 메인쿼리

 

1) 메인쿼리

- 실행의 결과가 조회되는 쿼리

- 서브쿼리에 의해 실행된 쿼리문의 결과에 의해 ㅔ인쿼리가 실행된다

 

2) 서브쿼리

- 메인쿼리의 안쪽에 위치한 쿼리

- 서브쿼리의 실행 결과가 메인쿼리의 조건이나 결과로 사용된다

- 서브쿼리에서는 ORDER BY절 사용 불가

- 서브쿼리의 사용 위치

* WHERE: 값의 결과가 1개로 나오는 결과일 경우 (여러개도 가능)

* HAVING: 메인쿼리에서 그룹행 함수를 사용하고 그룹에 대한 조건을 서브쿼리로 사용가능

* FROM

* SELECT

* INSERT 명령의 INTO

* UPDATE 명령의 SET

 

- 서브쿼리의 종류

단일행 서브쿼리 : 서브쿼리의 결과가 하나만 나오는 경우

복수행 서브쿼리 : 서브쿼리의 결과가 하나 이상 나오는 경우

WHERE절IN 연산자와 사용

IN, ANY, ALL, EXISTS

 

*/

 

 

-- [문제 1] 사원번호가 109번인 사원의 급여보다 급여가 많은 사원의 이름과 담당업무 조회

-- 1) 일반쿼리로 2번 나눠 처리한 경우

select salary

from employees

where employee_id = 109; -- 9000

 

select first_name, job_id

from employees

where salary > 9000;

 

 

-- 2) 서브쿼리로 처리한 경우 (단일행 서브쿼리)

select first_name, job_id

from employees

where salary > (select salary

from employees

where employee_id = 109);

 

 

 

-- [문제 2] 162번 사원의 급여와 동일한 급여를 받는 사원의 명단을 조회 (이름, 급여, 부서번호)

select first_name, salary, department_id

from employees

where salary = (select salary

from employees

where employee_id = 162);

 

 

-- [문제 3] from절에서 사용

select employee_id, first_name, salary, department_id

from employees

where department_id = 50;

 

select tbl.* from

(select employee_id, first_name, salary, department_id

from employees

where department_id = 50) tbl

where salary > 4000;

 

 

 

** 일련번호 rownum (동적으로 붙여주는 순서번호)

select rownum, first_name

from employees

where department_id = 80;

 

 

-- 일련번호를 기준으로 조건 걸기(무조건 1번부터 조회 가능)

select rownum, tbl.* from

(select employee_id, first_name, salary, department_id

from employees

where department_id = 50) tbl

where

salary > 3000

and

rownum between 1 and 10;

 

 

-- 동적으로 사용되지 않도록 안쪽에 사용

select tbl.* from

(select rownum as RNO, employee_id, first_name, salary, department_id

from employees

where department_id = 50) tbl

where

salary > 3000

and

RNO between 11 and 20;

 

 

-- [문제 4] 사원번호가 101인 사원의 담당업무가 같은 사원들의 목록을 조회 (사원번호, 이름, 담당업무)

select employee_id, first_name, job_id

from employees

where job_id = (select job_id

from employees

where employee_id = 101);

 

 

-- [문제 5] 03년도 이전에 입사한 직원의 일련번호화 이름, 급여, 입사일, 부서번호를 조회

-- 이중 3번째로 급여가 많은 직원의 명단을 재조회

-- 3중 서브쿼리

select * from

(select rownum rno, temp.* from

(select first_name, salary, hire_date, department_id

from employees where hire_date < '03/01/01'

order by salary desc

) temp

)tmp

where rno = 3;

 

 

-- [문제 6] 이름이 'Bruce', 'Daniel'이라는 직원의 성을 조회

select first_name, last_name

from employees

where first_name in ('Bruce', 'Daniel');

 

 

-- 2개의 데이터를 나란히 출력하기

select

(select last_name from employees where first_name = 'Bruce') as "Bruce의 성",

(select last_name from employees where first_name = 'Daniel') as "Daniel의 성"

from dual;

 

 

** 복수행 서브쿼리

 

-- 1) in 연산자와 함께한 복수행 서브쿼리

-- [문제 7] in 연산자와 함께 30번 부서의 직급과 동일한 직급이 다른 팀에도 있는지 조회

select * from employees

where job_id in (select distinct job_id

from employees

where department_id = 30);

 

 

** ANY / ALL 연산자

> ANY, < ANY, >= ANY, <= ANY, != ANY, = ANY

 

 

-- 2) 5800 가장 작은값, 8200 가장 큰값

select salary, job_id

from employees

where job_id = 'ST_MAN'

order by 1;

 

 

-- > any : 서브쿼리에서 추출된 어느 값보다 큰 값이어야 하므로 --> 결국, 가장 작은값보다 큰 값이 조회된다.

select first_name, salary

from employees

where salary > any (select salary

from employees

where job_id = 'ST_MAN');

 

 

-- > all : 서브쿼리에서 추출된 어느 값보다 큰값이 메인쿼리에서 사용되므로 가장 큰값보다 더 큰 값이 조회된다.

select first_name, salary

from employees

where salary > all (select salary

from employees

where job_id = 'ST_MAN');

 

 

-- [문제 8] 'ST_MAN' 직군의 급여 중에서 가장 적게 받는 급여보다 더 적게 받는 가람의 이름, 급여를 조회

select first_name, salary

from employees

where salary < any(select salary

from employees

where job_id = 'ST_MAN');

 

 

-- [문제 9] 직군이 'REP'인 직원들이 받는 급여와 동일한 급여를 받는 직원의 사원번호, 이름, 직급, 급여를 조회

select employee_id, first_name, job_id, salary

from employees

where salary = any (select salary

from employees

where job_id like '%REP');

 

 

** EXISTS : 서브쿼리에서 질의한 결과에 만족하는 행이 존재하면 메인쿼리 실행

select department_name

from departments

where exists (select department_id

from employees

where department_id = 80);

 

 

-- [문제 10] 성이 'Chen'인 직원이 존재하면 그 직원의 부서명, 이름, , 급여

select d.department_name, e.first_name, e.last_name, e.salary

from employees e join departments d

on e.department_id = d.department_id

where exists (select first_name, last_name

from employees

where last_name = 'Chen')

and last_name = 'Chen';

 

 


-- [문제] 입사년도별 입사인원이 가장 적은 해의 정보를 출력

select min(입사인원) from

(

select to_char(hire_date, 'YYYY') as 입사년도, count(*) as 입사인원

from employees

group by to_char(hire_date, 'YYYY')

order by 1

) temp ;

 

 

[연습문제

-- 1. 80번 부서의 급여의 평균, 최고, 최저, 인원수를 구하시오.

select avg(salary), max(salary), min(salary), count(*)

from employees

where department_id = 80;

 

 

-- 2. 각 부서별 급여의 평균, 최고, 최저, 인원수를 구하시오.

select avg(salary), max(salary), min(salary), count(*)

from employees

group by department_id;

 

 

-- 3. 각 부서별 평균 급여, 전체 급여, 최저 급여를 구하여 평균 급여가 많은 순으로 조회

-- , 부서번호거 null이면 출력하지 않는다

select avg(salary), sum(salary), min(salary)

from employees

group by department_id

order by 1 desc;

 

 

-- 4. 각 부서별 같은 업무를 하는 사람의 인원수를 구하여 부서번호, 업무명, 인원수를 출력

select department_id, job_id, count(*)

from employees

group by department_id, job_id;

 

 

-- 5. 같은 업무를 하는 사람의 수가 4명 이상인 업무와 인원수를 출력

select job_id, count(*)

from employees

group by department_id, job_id

having count(*) >= 4;