본문 바로가기

데이터베이스/Oracle

서브쿼리(SubQuery) (1)

--SubQuery
절차, 일의 순서 가지고 있음.

SELECT SQL 구문에 SELECT 구문이 또 들어가는것

--위치에 따른 분류
(1) SubQuery : WHERE절에서 사용
(2) INLINE VIEW : FROM절에서 사용하는 서브쿼리
(3) Scalar Query : SELECT절에서 사용


--SubQuery 결과행 수에 따른 분류
(1)Single Row SubQuery : main query/OUTER쿼리와 비교 시 일반비교연산자 사용가능(=, <>)

                                         (서브쿼리 결과가 한개 행만 반환하는 경우)

SELECT department_id, MAX(salary), employee_id, first_name
FROM employees
WHERE salary = (SELECT department_id, MAX(salary)
                FROM employees
                GROUP BY department_id
);

--여기서 SELECT department_id, MAX(salary), employee_id, first_name
--FROM employees WHERE salary =  부분이 메인쿼리

--SubQuery 결과행 수에 따른 분류

(2)Multi Row SubQuery : main query와 비교시 특수비교연산자 사용(IN, ANY>, ANY<, ALL>, ALL<)

                                        (서브쿼리 결과가 여러 행 반환하는 경우)

서브쿼리가 여러행 반환
서브쿼리의 결과 행이 여러 행일 경우에는 메인 쿼리와 비교시 일반 비교연산자 쓸 수 없다 에러가 발생함. 특수한 비교연산자 사용해야한다. any,all

SELECT department_id, MAX(salary), employee_id, first_name
FROM employees
WHERE salary IN (SELECT department_id, MAX(salary)
                 FROM employees
                 GROUP BY department_id
);
--이거도 에러. 메인쿼리 서브쿼리 컬럼의 갯수가 동일해야함
SELECT department_id, employee_id, first_name, salary
FROM employees
WHERE (department_id, salary) IN (SELECT department_id, MAX(salary)
                                  FROM employees
                                  GROUP BY department_id
);
--최대급여자의 사번, 이름, 급여를 출력하시오
--1) 최대급여를 계산한다
SELECT MAX(salary)
FROM employees;
--얘가 한개 행만 반환해서 Single Row SubQuery
--2) 1)과 같은 급여를 받는 사원의 사번, 이름, 급여를 출력하시오
SELECT employee_id, first_name, salary
FROM employees
WHERE salary = (SELECT MAX(salary)
                FROM employees
);
--사원들의 평균급여보다 많은 급여를 받는 급여자의 사번, 이름, 급여를 출력하시오
--1)사원들의 평균급여 계산한다.
SELECT AVG(salary)
FROM employees;
--2) 1)보다 많은 급여를 받는 급여자의 사번, 이름, 급여를 출력하시오
SELECT employee_id, first_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary)
                FROM employees
);

JOIN도 가능하고 SubQuery도 가능한 상황이면 SubQuery를 사용해라

--부서별 최대급여를 받는 사원의 부서번호, 사번, 이름, 급여를 출력하시오
SELECT department_id, MAX(salary), employee_id, first_name
FROM employees
GROUP BY department_id;--(X)

집계함수는 GROUP BY절에서 사용한 컬럼과 함께 SELECT절에서 사용가능
GROUP BY 없으면 실행안됨

SELECT department_id, MAX(salary), employee_id, first_name
FROM employees
GROUP BY department_id, employee_id, first_name; --(X)

실행은 되나 옳지않은 결과, 사원별 최대 금액만 나옴

 

--Multi Row SubQuery : IN는 = ANY 어떤 것이라도 같음. (OR 연산자와 같은 의미로 판단)
                                       > ANY 최소값보다 크다. any보다 크다 
                                       < ANY 최대값보다 작다. any보다 작다
                                       > ALL 최대값보다 크다. 든것보다 크다. ALL보다 크다 
                                       < ALL 최대값보다 작다. 모든것보다 작다. ALL보다 작다
sub 결과가 10, 20, 40있을 때 10과 같거나 20과 같거나 40과 같거나, 이것들보다 커야함. 이것들보다 작아야함.
NOT IN은 or의 반대값

--부서별 최대급여를 받는 사원의 부서번호, 사번, 이름, 급여를 출력하시오
--1) 부서별 최대급여를 계산한다
SELECT department_id, MAX(salary)
FROM employees
GROUP BY department_id;
--2) 1)과 같은 급여를 받는 사원의 부서번호, 사번, 이름, 급여를 출력하시오
SELECT department_id, MAX(salary), employee_id, first_name
FROM employees
WHERE salary = (SELECT department_id, MAX(salary)
                FROM employees
                GROUP BY department_id
);

NOT IN 예제

--부하직원이 있는 관리자의 관리자번호, 관리자 이름 출력하시오.
SELECT employee_id, first_name
FROM employees
WHERE employee_id IN (SELECT manager_id
                      FROM employees);
                      
SELECT employee_id, first_name
FROM employees
WHERE employee_id IN (null, 100, 102, 103, 101, 108 …);

--employee_id = null or employee_id = 100 or employee_id = 102 or employee_id = 103 or ....

→ null은 못함. 첫번째는 안됨. 나머지만 조건 추출

--OR의 반대, NOT IN 연산자
employee_id <> null and employee_id <> 100 and employee_id <> 102 ....

employee_id <> null null값은 비교대상이 되지 못하니 결과가 null
and라서 결과 조건 맞는 연산자 없음. NOT IN 연산자 위험하다. 결과 행수가 0건이 됨.
NOT IN 연산자 쓸땐 서브쿼리 null 값 있는지 없는지 확인.

--부하직원이 없는 모든 사원의 사번, 이름을 출력하시오.
SELECT employee_id, first_name
FROM employees
WHERE employee_id NOT IN (SELECT manager_id
                          FROM employees);
                          
SELECT employee_id, first_name
FROM employees
WHERE employee_id NOT IN (null, 100, 102, 103, 101, 108 …);

SELECT employee_id, first_name
FROM employees
WHERE employee_id NOT IN (SELECT NVL(manager_id, -1)
                          FROM employees);--89명
                          
--위와 동일하게 이 방법도 가능						  
SELECT employee_id, first_name
FROM employees
WHERE employee_id NOT IN (SELECT manager_id
                          FROM employees
                          WHERE manager_id IS NOT NULL);--89명

NOT IN 예제 2

SELECT name
FROM Customer
MINUS
SELECT name
FROM Customer
WHERE custId IN (SELECT custId FROM Orders);

-- NOT IN 연산자로 변경
SELECT name
FROM customer
WHERE custid NOT IN (SELECT custid FROM orders);

 

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

서브쿼리 예제  (0) 2023.08.22
서브쿼리(SubQuery) (2)  (0) 2023.08.22
집합연산자  (0) 2023.08.22
JOIN 예제  (0) 2023.08.22
JOIN  (0) 2023.08.21