[Oracle] 서브쿼리의 분류

2015. 10. 3. 23:01

간단히 다음과 같이 분류할 수 있다.

인라인뷰 : 메인쿼리의 FROM 절에 사용된 서브쿼리 (뷰처럼 사용된다고 해서 붙여진 이름)

서브쿼리 : (좁은 의미로) WHERE 절에 사용되는 서브쿼리, 폭 넓게는 서브쿼리 전체를 통칭 하는듯...

스칼라서브쿼리 : 서브쿼리 중에서도 특별히 SELECT 절에 컬럼처럼 사용된 서브쿼리를 말함.

* 틀린 부분있으면 지적해주시면 감사하겠습니다~!

곰돌곰둘 Oracle_DB_Unix admin/(3)뇌자극 오라클 PL/SQL

[Oracle] 연관성 있는 서브쿼리와 연관성 있는 서브쿼리

2015. 10. 3. 22:15

연관성있는 서브쿼리의 대표적인 예는 EXISTS 연산자를 사용하는 서브쿼리이다.


예제)

*연관성 없는 서브쿼리

select count(*) from employees

where department_id in (select department_id

from departments

where manager_id is not null);


--> EXISTS로 전환

*연관성 있는 서브쿼리

select count(*) from employees emp

where exists (select 1

from departments dep

where dep.manager_id is not null

and emp.department_id = dep.department_id);


--> 데이터의 연관성이 있다는 의미는 서브쿼리와 메인쿼리 사이에서 조인이 사용되었음을 의미한다.

* 연관성 있는 서브쿼리의 경우에는 조인을 수반하므로 반드시 별칭을 사용해야 한다.


(정의) 연관성 있는 서브쿼리: 메인쿼리에 독립적이지 않고 연관관계, 즉 조인을 통해 연결되어 있는 쿼리를 말한다.


<연관성 있는 서브쿼리의 활용>

예제)

* 일반 조인 사용 시

select emp.first_name||' '||emp.last_name emp_names,

emp.department_id,

dep.department_name

from employees emp, departments dep

where emp.department_id=dep.department_id;


* 연관성 있는 서브쿼리 사용 시

select emp.first_name||' '||emp.last_name emp_names,

emp.department_id,

(select dep.department_name

from departments dep

where dep.department_id = emp.department_id) dep_name

from employees emp;


연관성 있는 서브쿼리는 이와 같이 select list에 자주 쓰인다. 연관성 없는 서브 쿼리도 select list에 올 수는 있지만 실제로 그런 경우는 거의 없다.

왜 그럴까?

연관성 없는 서브쿼리의 경우 다중 로우를 추출하는 경우가 많음.

반면 연관성 있는 서브쿼리의 경우 메인쿼리와의 연관성(=조인)이 있기 때문에 SELECT LIST에 올 수 있으며, 이러한 경우 단일 로우를 추출하게 된다.


* 뇌를 자극하는 오라클 프로그래밍 (홍형경 저) 참조함.

'Oracle_DB_Unix admin > (3)뇌자극 오라클 PL/SQL' 카테고리의 다른 글

PL/SQL 문장과 커서  (0) 2015.10.08
PL/SQL 객체  (0) 2015.10.04
[Oracle] 인라인뷰  (0) 2015.10.03
[Oracle] 서브쿼리의 분류  (0) 2015.10.03
[Oracle] EXISTS 연산자의 활용  (0) 2015.10.03

곰돌곰둘 Oracle_DB_Unix admin/(3)뇌자극 오라클 PL/SQL

[Oracle] EXISTS 연산자의 활용

2015. 10. 3. 21:23

문제: 부서 번호가 30, 60, 90인 직원 출력하기

(1) IN 연산자 활용시 
select department_id, employee_id from employees

where  department_id in (30,60,90)

order by 1, 2;


(2) EXISTS 연산자 활용 시

select emp.department_id, emp.employee_id

from employees emp

where exists

(select dep.department_id

from departments dep

where dep.department_id in (30, 60, 90)

and emp.department_id=dep.department_id)

order by 1, 2;


--> 변환(동일한 결과값 출력됨)


(3) EXISTS 연산자 활용 시

select emp.department_id, emp.employee_id

from employees emp

where exists

(select 1

from departments dep

where dep.department_id in (30, 60, 90)

and emp.department_id=dep.department_id)

order by 1, 2;


<EXISTS의 특징>

(1)EXISTS는 오직 서브쿼리만 쓸 수 있다.

(2)서브쿼리에서 조인을 사용한다.

(3)EXISTS는 서브쿼리의 결과가 있느냐 없느냐만 체크한다.

(IN 이 WHERE 조건절에 해당하는 레코드의 컬럼값을 출력하는 것과는 대비하여-)

  *EXISTS는 존재하느냐 존재하지 않느냐의 여부만 체크하기 때문에 서브쿼리의 SELECT 리스트에는 등장하는 값과는 상관없이 서브쿼리의 결과로 반환되는 로우가 있느냐 없느냐만 중요한 것이다.


<NOT IN과 NOT EXISTS>

IN과 EXISTS는 동일한 결과값을 출력한다.

반면 NOT IN과 NOT EXISTS는 결과값이 다를 수 있다. 바로 NOT IN 은 NULL 값을 포함하지 않기 때문이다.


예제)

department_id 가 null인 레코드 1건 존재-->

select employee_id, department_id

from employees

where department_id is null;

1개 recored


NOT IN -->

select department_id, employee_id from employees

where  department_id not in (30,60,90)

order by 1, 2;

92개 records


NOT EXISTS -->

select emp.department_id, emp.employee_id

from employees emp

where not exists

(select 1

from departments dep

where dep.department_id in (30, 60, 90)

and emp.department_id=dep.department_id)

order by 1, 2;

93개 records


※차이가 발생하는 이유

IN은 OR이다.

department_id IN (30, 60, 90) --> department_id = 30 or department_id = 60 or department_id = 90 으로 바꿔 쓸 수 있다.

NOT IN의 경우 (AUB)^C 이므로 A^C교집합B^C으로 쓸 수 있다.

department_id NOT IN (30, 60, 90) --> (a)department_id <> 30 and (b)department_id <> 60 and (c)department_id <> 90 으로 바꿔 쓸 수 있다.

문제는 null 값은 '=', '<>' 연산을 했을때 TRUE/FALSE를 반환하지 않고 UNKNOWN을 반환한다는 것에 있다. 따라서 department_id가 null인 178번 사원은 (a), (b), (c) 어디에도 포함되지 않고, 따라서 반환되지 않는다.


반면 EXISTS의 경우 해당 로우의 존재여부만 체크하기 때문에, NOT EXISTS는 department_id 값이 30, 60, 90이 아닌 모든 로우를 조회하게 되며, 따라서 department_id가 null인 값도 출력에 포함되는 것이다.


<IN과 EXISTS의 활용>

컬럼값에 대해 비교할 값이 문자나 숫자 등의 상수 리스트를 사용할 경우 IN을 사용하도록 하고, 만약 서브쿼리를 사용한다면 IN보다는 EXISTS를 사용하는 것이 훨씬 성능이 좋다.


* 뇌를 자극하는 오라클 프로그래밍 (홍형경 저) 참조함.

곰돌곰둘 Oracle_DB_Unix admin/(3)뇌자극 오라클 PL/SQL