바깥쪽쿼리 : 메인쿼리
안에 삽입된 쿼리 : 서브쿼리
SQL> select *
2 from emp
3 where sal>(select avg(sal) from emp);
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7566 JONES MANAGER 7839 81/04/02 2975 20
7698 BLAKE MANAGER 7839 81/05/01 2850 30
7782 CLARK MANAGER 7839 81/06/09 2450 10
7788 SCOTT ANALYST 7566 82/12/09 3000 20
7839 KING PRESIDENT 81/11/17 5000 10
7902 FORD ANALYST 7566 81/12/03 3000 20
6 rows selected.
SQL> select *
2 from emp
3 where job = (select job
4 from emp
5 where empno=7566);
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7566 JONES MANAGER 7839 81/04/02 2975 20
7698 BLAKE MANAGER 7839 81/05/01 2850 30
7782 CLARK MANAGER 7839 81/06/09 2450 10
select ename,deptno, sal
from emp
where sal>(select max(sal)
from emp
where deptno=20);
select ename,hiredate,sal
from emp
where sal>(select avg(sal)
from emp
where substr(hiredate,1,2)=82);
where substr(hiredate,1,2)=82대신
where hiredate like '82%'도 가능
select ename, empno, deptno
from emp
where deptno in (select deptno
from emp
where ename like'%T%');
-> 동일한 컬럼에 값이 여러 개 나와서 in연산자 씀
select ename,sal
from emp
where sal<any(800,1250,1600);
select ename,sal
from emp
where sal>any(800,1250,1600);
select ename,sal
from emp
where sal<all (900,1250,1600);
select ename,sal
from emp
where sal>all (900,1250,1600);
select empno,deptno,sal
from emp
where sal in(select min(sal)
from emp
where deptno is not null
group by deptno);
:두개 이상의 컬럼을 리턴하는 서브쿼리
SQL> select * from emp where deptno=20;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80/12/17 800 20
7566 JONES MANAGER 7839 81/04/02 2975 20
7788 SCOTT ANALYST 7566 82/12/09 3000 20
7876 ADAMS CLERK 7788 83/01/12 1100 20
7902 FORD ANALYST 7566 81/12/03 3000 20
SQL> update emp
2 set sal = 1300
3 where empno = 7876;
1 row updated.
SQL> select * from emp where deptno=20;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80/12/17 800 20
7566 JONES MANAGER 7839 81/04/02 2975 20
7788 SCOTT ANALYST 7566 82/12/09 3000 20
7876 ADAMS CLERK 7788 83/01/12 1300 20
7902 FORD ANALYST 7566 81/12/03 3000 20
SQL> commit;
Commit complete.
SQL> select empno,deptno,sal
2 from emp
3 where sal in(select min(sal)
4 from emp
5 where deptno is not null
6 group by deptno);
EMPNO DEPTNO SAL
---------- ---------- ----------
7369 20 800
7876 20 1300
7900 30 950
7934 10 1300
SQL> select empno,deptno,sal
2 from emp
3 where (deptno,sal) in(select deptno,min(sal)
4 from emp
5 where deptno is not null
6 group by deptno);
EMPNO DEPTNO SAL
---------- ---------- ----------
7900 30 950
7369 20 800
7934 10 1300
in연산자는 한개라도 일치하면 나오는거고, deptno로 그룹화해서 최솟값을 구하고, 이후 그 최소값만으로 비교를해서 다른 그룹의 최솟값과 일치해도 출력됨. 그래서 다중컬럼 서브쿼리에서 최솟값과 그룹값 두개를 다 비교해서 둘다 일치하는 값만 출력
-> 성능낮음, 상관형 서브쿼리로 만든 코드 업데이트하는 업무 맡을 수 있으니 알아야 함
[실행흐름]
1. 메인쿼리에서 참조할 값을 받아서 서브쿼리를 실행
<2. 서브쿼리의 실행결과를 컬럼이 한 개 row가 한개의 결과를 반환>
3. 메인쿼리에서 서브쿼리의 결과를 받아서 메인쿼리 실행
4. 1번에서 3번까지를 테이블의 레코드 갯수만큼 반복해서 실행
SQL> select *
2 from emp
3 where sal > (select avg(sal)
4 from emp
5 where job='ANALYST');
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7839 KING PRESIDENT 81/11/17 5000 10
SQL> select *
2 from emp
3 where sal > (select avg(sal)
4 from emp
5 where deptno=20);
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7566 JONES MANAGER 7839 81/04/02 2975 20
7698 BLAKE MANAGER 7839 81/05/01 2850 30
7782 CLARK MANAGER 7839 81/06/09 2450 10
7788 SCOTT ANALYST 7566 82/12/09 3000 20
7839 KING PRESIDENT 81/11/17 5000 10
7902 FORD ANALYST 7566 81/12/03 3000 20
6 rows selected.
-> 레코드 갯수만큼 서브쿼리가 실행되므로 성능저하의 원인이 될수있다.
SQL> select *
2 from emp e
3 where sal>(select avg(sal)
4 from emp
5 where deptno=e.deptno);
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7499 ALLEN SALESMAN 7698 81/02/20 1600 300 30
7566 JONES MANAGER 7839 81/04/02 2975 20
7698 BLAKE MANAGER 7839 81/05/01 2850 30
7788 SCOTT ANALYST 7566 82/12/09 3000 20
7839 KING PRESIDENT 81/11/17 5000 10
7902 FORD ANALYST 7566 81/12/03 3000 20
6 rows selected.
SQL> select e.*
2 from emp e,(select deptno, avg(sal) avgsal
3 from emp
4 group by deptno) s
5 where e.deptno = s.deptno and
6 e.sal>s.avgsal;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7499 ALLEN SALESMAN 7698 81/02/20 1600 300 30
7566 JONES MANAGER 7839 81/04/02 2975 20
7698 BLAKE MANAGER 7839 81/05/01 2850 30
7788 SCOTT ANALYST 7566 82/12/09 3000 20
7839 KING PRESIDENT 81/11/17 5000 10
7902 FORD ANALYST 7566 81/12/03 3000 20
6 rows selected.
-> 리소스 훨씬 적고 성능높음
select employee_id, concat(concat(first_name,' '),last_name ) as name, hire_date
from employees
where hire_date<(select hire_date
from employees
where first_name='Lisa')
and hire_date like '05%';
select first_name,salary,department_name
from employees e, departments d
where e.department_id=d.department_id and
department_name='Sales' and
salary<(select avg(salary)
from employees
where department_id=100);
select employee_id,last_name,hire_date,salary
from employees
where employee_id = (select manager_id
from employees
where last_name='De Haan');
https://blog.naver.com/heaves1/223410651869
[조인]
select e.first_name, e.salary
from employees e, employees m
where e.manager_id=m.employee_id
and e.salary>m.salary
이건 그냥 hr계정으로 연습해본거
select e.employee_id,e.first_name, m.manager_id,m.first_name
from employees e, employees m
where e.manager_id=m.employee_id
select m.first_name 관리자명, count(e.employee_id) 인원수
from employees e, employees m
where e.manager_id=m.employee_id
group by m.first_name;
[서브쿼리]
select department_name, avg(salary)
from departments d, employees e
where d.department_id=e.department_id
group by department_name
having avg(salary)<=(select avg(salary)
from employees
where department_id=30);
select employee_id, last_name, salary, department_id
from employees
where (department_id, salary) in (select department_id, max(salary)
from employees
group by department_id)
order by salary desc;
select first_name, last_name, salary
from (select *
from jobs j, employees e
where j.job_id=e.job_id
and job_title ='Sales Representative'
and salary between 9000 and 10000);
: 데이터를 특정 기준에 따라 정렬하고 정렬된 데이터를 상위 N개만 조회하기 위해 적용
SQL> select rownum, ename, sal
2 from emp;
ROWNUM ENAME SAL
---------- -------------------- ----------
1 SMITH 800
2 ALLEN 1600
3 WARD 1250
4 JONES 2975
5 MARTIN 1250
6 BLAKE 2850
7 CLARK 2450
8 SCOTT 3000
9 KING 5000
10 TURNER 1500
11 ADAMS 1300
12 JAMES 950
13 FORD 3000
14 MILLER 1300
15 RM 500
16 슈가 500
16 rows selected.
SQL> select rownum, ename, sal
2 from emp
3 where rownum<4;
ROWNUM ENAME SAL
---------- -------------------- ----------
1 SMITH 800
2 ALLEN 1600
3 WARD 1250
이렇게 하면 일련번호가 뒤죽박죽이 됨
SQL> select rownum, ename, sal
2 from emp
3 where rownum<4
4 order by sal desc;
ROWNUM ENAME SAL
---------- -------------------- ----------
2 ALLEN 1600
3 WARD 1250
1 SMITH 800
서브쿼리안에서 미리 정렬 후 뽑으면 일련번호 순서대로 나옴
SQL> select rownum,ename,sal
2 from(select *
3 from emp
4 order by sal desc);
ROWNUM ENAME SAL
---------- -------------------- ----------
1 KING 5000
2 FORD 3000
3 SCOTT 3000
4 JONES 2975
5 BLAKE 2850
6 CLARK 2450
7 ALLEN 1600
8 TURNER 1500
9 MILLER 1300
10 ADAMS 1300
11 WARD 1250
12 MARTIN 1250
13 JAMES 950
14 SMITH 800
15 슈가 500
16 RM 500
16 rows selected.
서브쿼리만 보면 이런모양
select *
from emp
order by sal desc
;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
------ -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7839 KING PRESIDENT 81/11/17 5000 10
7902 FORD ANALYST 7566 81/12/03 3000 20
7788 SCOTT ANALYST 7566 82/12/09 3000 20
7566 JONES MANAGER 7839 81/04/02 2975 20
7698 BLAKE MANAGER 7839 81/05/01 2850 30
7782 CLARK MANAGER 7839 81/06/09 2450 10
7499 ALLEN SALESMAN 7698 81/02/20 1600 300 30
7844 TURNER SALESMAN 7698 81/09/08 1500 0 30
7934 MILLER CLERK 7782 82/01/23 1300 10
7876 ADAMS CLERK 7788 83/01/12 1300 20
7521 WARD SALESMAN 7698 81/02/22 1250 500 30
7654 MARTIN SALESMAN 7698 81/09/28 1250 1400 30
7900 JAMES CLERK 7698 81/12/03 950 30
7369 SMITH CLERK 7902 80/12/17 800 20
8888 슈가 24/04/09 500
7777 RM 24/04/09 500
조건 넣어주면 원하는 대로 나옴
SQL> select rownum,ename,sal
2 from(select *
3 from emp
4 order by sal desc)
5 where rownum <4;
ROWNUM ENAME SAL
---------- -------------------- ----------
1 KING 5000
2 SCOTT 3000
3 FORD 3000
select mon as 월, cnt as 입사자
from(select to_char(hire_date,'MM') as mon, count(employee_id) as cnt
from employees
group by to_char(hire_date,'MM')
order by cnt desc) emp
where rownum<=3
order by 월;
from절에서 만들어지는 컬럼은 원래 물리적으로 하드디스크에 저장되어 있는 컬럼이 아니라 계산으로 만들어지는 컬럼이므로 컬럼명이 없습니다. 컬럼명이 없으면 오라클에서 연산에 사용할 수 없으므로 이 to_char(hire_date,'MM')와 같이 만들어진 컬럼을 메인 쿼리에서 액세스 하려면 반드시 컬럼명이 있어야 합니다.
메인쿼리에 오더바이가 지금 이 예제에는 없어도 결과가 나오는데 top-n쿼리를 만들때는 필수로 넣어주신다고 생각하시면 됩니다. 정렬이 되어있는 상태에서 rownum을 활용하는 것이 top-n쿼리이므로 그걸 강조하기 위해 넣은 것이고 테이블 alias또한 지금은 한 테이블만 가지고 작업하므로 없어도 결과가 나오지만 두 개 이상의 테이블을 이용해서 조인하는 경우 테이블명이 없으면 컬럼들을 액세스 할 수 없으므로 테이블 alias를 넣었습니다. 이예제는 둘 다 없어도 실행되는 예제예요
밑은 내가 푼 거
select mon 월, num 입사자
from (select substr(hire_date,4,2) mon, count(employee_id) num
from employees
group by substr(hire_date,4,2)
order by substr(hire_date,4,2) )
where rownum<4;
select first_name, salary, dname
from (select e.*, d.department_name dname
from employees e, departments d
where e.department_id=d.department_id
order by salary desc)
where dname='IT' and rownum<=3;
내가푼거
select first_name, salary, department_name
from (select first_name, salary, department_name
from departments d, employees e
where d.department_id=e.department_id
and department_name ='IT'
order by salary desc)
where rownum<4;
본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.