서브 쿼리(Sub-Query)란,
한 쿼리문 안에 포함된 또 다른 SELECT 문을 의미한다.
최종 결과를 출력하는 쿼리를 메인쿼리라고 한다면,
이를 위한 중간 단계 혹은 보조 역할을 하는
SELECT문을 서브쿼리라 한다.
***메인쿼리는 SELECT문 외에도
INSERT, UPDATE, MERGE, DELETE문도 가능하다.
하지만 서브쿼리는 SELECT문만 가능하다.
서브쿼리의 특징
메인쿼리와 서브쿼리의 관계는 주종 관계로서,
서브쿼리에 작성된 컬럼명은 메인쿼리의 컬럼명을 가져와서
사용할 수 있으나 그 역은 성립하지 않는다.
하나의 SQL 문을 기준으로 메인쿼리를 제외한 나머지
모든 SELECT문을 서브쿼리로 보면 된다.
하나의 메인쿼리 안에는 1개 이상의 서브쿼리를 사용할 수 있다.
(물론 필요없으면 안 써도 된다!)
실행 순서로 보면 서브쿼리가 먼저 실행되고
이후 메인쿼리가 실행된다.
서브쿼리의 결과를 메인쿼리에 적용하므로
서브쿼리의 리턴값(결과값)이
메인쿼리의 매개변수라고 볼 수도 있겠다.
서브쿼리의 종류
서브쿼리는 동작하는 방식이나 반환되는 데이터의 형태,
활용되는 위치를 기준으로 분류할 수 있다.
먼저 동작 방식을 기준으로 분류한 서브쿼리의 유형은 다음과 같다.
서브쿼리 종류 | 설명 |
비연관 서브쿼리 (Un-Correlated Sub-Query) |
- 서브쿼리가 메인쿼리의 컬럼을 가지고 있지 않은 형태 - 메인 테이블과 조인 조건이 걸리지 않는 서브쿼리를 말함 - 서브쿼리는 메인쿼리 없이 독자적으로 실행됨 - 메인쿼리에 서브쿼리에서 실행된 결과를 제공하는 용도로 사용 |
연관 서브쿼리 (Correlated Sub-Query) |
- 서브쿼리가 메인쿼리의 컬럼을 가지고 있는 형태 - 메인 테이블과 조인 조건이 걸린 서브쿼리를 말함 - 메인쿼리가 먼저 수행되어 얻은 데이터를 서브쿼리의 조건에 맞는지 확인하는 용도로 사용 |
반환되는 데이터 형태에 따른 서브쿼리의 종류는 다음과 같다.
서브쿼리 종류 | 설명 |
단일 행 서브쿼리 (Single Row Sub-Query) |
- 서브쿼리의 결과가 항상 1건 이하인 서브쿼리 - 단일 행의 비교 연산자에는 =, <, <=, >, >=, <> 등을 사용 |
다중 행 서브쿼리 (Multiple Row Sub-Query) |
- 서브쿼리의 실행 결과가 여러 건인 서브쿼리 - 다중 행 비교 연산자 사용 IN : 서브쿼리의 결과에 존재하는 임의의 값과 동일한 조건을 의미 ALL : 서브쿼리의 결과에 존재하는 모든 값을 만족하는 조건을 의미 ANY : 서브쿼리의 결과에 존재하는 어느 하나의 값이라도 만족하는 조건을 의미 EXIST : 서브쿼리의 결과를 만족하는 값이 존재 여부를 확인하는 조건을 의미 (다중 행 서브쿼리를 사용할 때는 다중 행 비교 연산자를 사용해야 함. 단일 행 서브쿼리를 사용할 때는 단일 행, 다중 행 비교 연산자 모두 사용가능함) |
다중 컬럼 서브쿼리 (Single Column Sub-Query) |
- 서브쿼리의 결과가 여러 컬럼으로 반환되는 서브쿼리 - 메인쿼리의 조건절에 여러 컬럼을 동시에 비교할 때, 서브쿼리와 메인쿼리에서 비교하는 컬럼 개수와 위치가 동일해야 함 |
서브쿼리의 위치를 기준으로도 서브쿼리를 구분할 수 있다.
서브쿼리 종류 | 설명 |
일반 서브쿼리 (= 스칼라 서브쿼리) (Scalar Sub-Query) |
- 서브쿼리의 위치가 SELECT 절에 있는 경우 - 단일 행 서브쿼리만 올 수 있음 - 컬럼의 튜플 수만큼 반복실행되므로 결과 산출까지 시간이 오래 걸림 |
인라인 뷰 (Inline Views) |
- 서브쿼리의 위치가 FROM 절에 있는 경우 - VIEW 처럼 결과가 동적으로 생성된 테이블 형태로 사용할 수 있음 |
중첩 서브쿼리 (Nested Sub-Query) |
- 서브쿼리의 위치가 WHERE 절이나 HAVING 절에 있는 경우 |
예시를 통해 살펴보자.
//employees 테이블 생성
CREATE TABLE employees (
employee_id NUMBER(5) PRIMARY KEY,
employee_name VARCHAR2(50),
department_id NUMBER(3),
salary NUMBER(10, 2)
);
//employees 테이블에 데이터 삽입
INSERT INTO employees
VALUES (1, 'John Doe', 101, 50000);
INSERT INTO employees
VALUES (2, 'Jane Smith', 102, 60000);
INSERT INTO employees
VALUES (3, 'Alice Johnson', 101, 55000);
INSERT INTO employees
VALUES (4, 'Bob Williams', 103, 62000);
INSERT INTO employees
VALUES (5, 'Mary Brown', 102, 58000);
예시 1 : 스칼라, 중첩 서브쿼리
부서별 평균 급여를 조회하고, 해당 부서의 평균 급여보다
높은 급여를 받는 직원을 조회한다.
출력되는 순서는 직원ID, 직원명, 급여, 소속 부터의 평균 급여이다.
SELECT
employee_id,
employee_name,
salary,
(SELECT AVG(salary)
FROM employees
WHERE department_id = e.department_id
) AS avg_department_salary
FROM employees e
WHERE salary > (
SELECT AVG(salary)
FROM employees
WHERE department_id = e.department_id
);
예시 2 : 인라인 뷰
부서별 평균 급여와 각 직원의 급여를 조회한다.
출력하려는 컬럼은 직원ID, 직원명, 급여, 소속부서의 평균급여이다.
SELECT e.employee_id, e.employee_name, e.salary, d.avg_salary
FROM employees e
JOIN (
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id) d
ON e.department_id = d.department_id;
예시 3 : 중첩 서브쿼리
부서별 최고 급여를 받는 직원을 조회한다.
출력하려는 컬럼은 직원ID, 직원명, 급여이다.
SELECT
employee_id,
employee_name,
salary
FROM
employees e1
WHERE
salary = (
SELECT MAX(salary)
FROM employees e2
WHERE e1.department_id = e2.department_id
);
'DB > SQL - Oracle' 카테고리의 다른 글
[SQL] 그룹 함수 (2) GROUPING SETS(특정 항목에 대한 소계 출력) (0) | 2024.02.18 |
---|---|
[SQL] 집합 연산자(Set Operator) - UNION, UNION ALL, INTERSECT, MINUS (0) | 2024.02.17 |
[SQL] 조인(JOIN) - Inner join, outer join, cross join (1) | 2024.02.16 |
[SQL] DML(데이터 조작어) - select *order by* 정렬 + ASCII(아스키코드) + UNICODE(유니코드) (0) | 2024.02.16 |
[SQL] DML(데이터 조작어) - select *group by, having* 그룹화 (0) | 2024.02.16 |