- Subquery는 다른 하나의 SQL 문장의 절에 NESTEDED된 SELECT 문장 이다.
- SELECT, UPDATE, DELETE, INSERT와 같은 DML문과 CREATE TABLE 또는 VIEW의 WHERE절이나 HAVING절에서 사용 된다.
- 보통 Subquery는 Main Query 이전에 한 번 실행된다.
- Subquery는 괄호로 묶어야 한다.
- 단일 행 연산자(=, >, >=, <, <=, <>, !=)와 다중 행 연산자(IN, NOT IN, ANY, ALL, EXISTS)들이 서브쿼리에 사용 된다.
- Subquery는 연산자의 오른쪽에 위치해야 한다.
🌱 서브쿼리의 유형
- 단일 행(Sing-Row) 서브쿼리 : SELECT 문장으로 부터 오직 하나의 행 만을 검색하는 질의이다.
- 다중 행(Multiple-Row) 서브쿼리 : SELECT 문장으로부터 하나 이상의 행을 검색하는 질의이다.
- 다중 열(Multiple-Column) 서브쿼리 : SELECT 문장으로부터 하나 이상의 컬럼을 검색하는 질의이다.
- FROM절상의 서브쿼리(INLINE VIEW) : FROM절상에 오는 서브쿼리로 VIEW처럼 작용 한다.
- 상관관계 서브 쿼리 : 바깥쪽 쿼리의 컬럼 중의 하나가 안쪽 서브쿼리의 조건에 이용되는 처리 방식 이다.
Single-Row Subquery
- SELECT 문장에서 오직 하나의 행(값)만 반환하는 Query이다
- 단일 행 연산자(=,>, >=, <, <=, <>, !=) 만 사용된다.
💊 empno가 7369의 job을 조회 한 후, job이 'CLERK'인 사원의 이름과 직업을 반환
SELECT ename,job
FROM emp
WHERE job = (SELECT job
FROM emp
WHERE empno = 7369);
Multiple-Row Subquery
- 하나 이상의 행을 반환하는 Subquery이다
- 단일 행 연산자를 사용하지 못하며, 다중 행 연산자(IN, NOT IN, ANY, ALL, EXISTS)만 사용이 가능하다.
🌱 IN 연산자
- IN 연산자는 하나의 컬럼이 여러개의 '=' 조건을 가지는 경우에 사용
- OR는 IN을 포함한다. IN을 사용해 표현할 수 있는 것은 당연히 OR로 표현할 수 있다.
- 하지만 OR로 표한한 것은 IN으로 표현하지 못할때가 있다. (OR에서 LIKE같은 연산자를 사용한 경우)
- IN은 반드시 하나의 컬럼이 비교되어야 하므로 나중에 인덱스 구성에 대한 전략을 수립할 때 유리하다.
- 그러므로 가능한 OR보다는 IN 을 사용하는 것이 좋다.
💊 부서별로 가장 급여를 많이 받는 사원의 정보를 출력하는 예제
SELECT empno,ename,sal,deptno
FROM emp
WHERE sal IN (SELECT MAX(sal)
FROM emp
GROUP BY deptno);
EMPNO ENAME SAL DEPTNO
----- ------ ------ -------
7698 BLAKE 2850 30
7788 SCOTT 3000 20
7902 FORD 3000 20
🌱 ANY 연산자
ANY 연산자는 Subquery의 여러 결과값 중 어느 하나의 값만 만족이 되면 행을 반환 한다.
💊 ALESMAN 직업의 급여보다 많이 받는 사원의 사원명과 급여 정보를 출력하는 예제
SELECT ename, sal
FROM emp
WHERE deptno != 20
AND sal > ANY (SELECT sal
FROM emp
WHERE job='SALESMAN');
ENAME SAL
---------- ----------
ALLEN 1600
BLAKE 2850
CLARK 2450
...
🌱 ALL 연산자
ALL 연산자는 Subquery의 여러 결과값 중 모든 결과 값을 만족해야 행을 반환 한다.
💊 모든 SALESMAN직업의 급여보다 많이받는 사원의 사원명과 급여정보를 출력하는예제
SELECT ename, sal
FROM emp
WHERE deptno != 20
AND sal > ALL (SELECT sal
FROM emp
WHERE job='SALESMAN');
ENAME SAL
---------- --------
CLARK 2450
BLAKE 2850
KING 5000
🌱 EXISTS 연산자
- EXISTS 연산자는 Subquery 데이터가 존재하는가를 체크해 존재 여부(TRUE,FALSE)를 결과로 반환한다.
- EXISTS절에는 반드시 메인 쿼리와 연결이 되는 조인 조건을 가지고 있어야 한다.
- subquery에서 결과 행을 찾으면, inner query 수행을 중단하고 TRUE를 반환한다.
-- 아래 예처럼 emp 테이블을 통해 사원들이 속한 부서번호의 정보만 조회하는 경우
-- 추출하고자 하는 대상은 dept 테이블이지만 emp 테이블과 조인하여 부서번호를
-- 체크해야 한다.
-- 두 테이블의 관계가 1 : M 이므로 불필요하게 EMP 테이블을 모두 액세스하고
-- DISTINCT로 중복 제거를 한다.
SELECT DISTINCT d.deptno, d.dname
FROM dept d, emp e
WHERE d.deptno = e.deptno;
-- EXISTS를 사용하는 Subquery로 변경
-- 추출하고자 하는 대상만을 FROM절에 놓고 emp테이블은 체크만 하기위해
-- EXISTS절에 위치시켰으며 이로 인해 수행속도가 대폭 감소하게 된다.
SELECT d.deptno, d.dname
FROM dept d
WHERE EXISTS
(SELECT 1
FROM emp e
WHERE e.deptno = d.deptno);
Multiple-Column Subquery
결과 값이 두 개 이상의 컬럼을 반환하는 Subquery이다
🌱 Pairwise(쌍비교) Subquery
Subquery가 한 번 실행되면서 두 개 이상의 컬럼을 검색해서 주 쿼리로 넘겨 준다.
SELECT empno, sal, deptno
FROM emp
WHERE (sal, deptno) IN (SELECT sal, deptno
FROM emp
WHERE deptno = 30
AND comm is NOT NULL);
EMPNO SAL DEPTNO
---------- ---------- ----------
7521 1250 30
7654 1250 30
7844 1500 30
7499 1600 30
🌱 Nonpairwise(비쌍비교) Subquery
WHERE 절에서 두 개 이상의 서로 다른 Subquery가 사용되어서 결과 값을 주 쿼리로 넘겨 준다.
SELECT empno, sal, deptno
FROM emp
WHERE sal IN (SELECT sal
FROM emp
WHERE deptno = 30
AND comm is NOT NULL);
AND deptno IN (SELECT deptno
FROM emp
WHERE deptno = 30
AND comm is NOT NULL);
EMPNO SAL DEPTNO
---------- ---------- ----------
7521 1250 30
7654 1250 30
7844 1500 30
7499 1600 30
🌱 Null Values in a Subquery
서브쿼리에서 NULL 값이 반환 되면 주 쿼리 에서는 어떠한 행도 반환되지 않는다.
Inline View (From절 Subquery)
- FROM절에 오는 Subquery이다.
- FROM절에서 원하는 데이터를 조회하여 가상의 집합을 만들어 조인을 수행하거나 가상의 집합을 다시 조회 할 때 사용한다.
- Inlivew View 안에 또 다른 Inline View가 올 수 있다.
💊 부서번호 20의 평균 급여보다 크고, 부서번호 20에 속하지 않은 관리자를 조회하는 예제
SELECT b.empno, b.ename, b.job, b.sal, b.deptno
FROM (SELECT empno
FROM emp
WHERE sal >(SELECT AVG(sal)
FROM emp
WHERE deptno = 20)) a, emp b
WHERE a.empno = b.empno
AND b.mgr is NOT NULL
AND b.deptno != 20;
EMPNO ENAME JOB SAL DEPTNO
----- --------- --------- ------- ---------
7698 BLAKE MANAGER 2850 30
7782 CLARK MANAGER 2450 10
Scalar Subquery
SELECT 절에서 사용하는 Subquery 이다.
특징
- 한 개의 로우만 반환 한다.
- 메인 쿼리에서 추출되는 데이터 건 수 만큼 수행되기 때문에 조인으로 수행 될 때보다 수행회수가 적을 수 있다.
- 일치하는 값이 없는 경우 NULL을 반환 한다.
- 코드성 테이블에서 코드값을 조회 할 때, 불필요한 조인을 하지 않기 위해 많이 사용한다.
💊 직업이 ‘MANAGER’인 사원의 사원명, 부서명을 조회하는 예제
SELECT ename,
(SELECT dname FROM dept d WHERE d.deptno = e.deptno) deptno
FROM emp e
WHERE job ='MANAGER';
ENAME DEPTNO
---------- --------------
JONES RESEARCH
BLAKE SALES
CLARK ACCOUNTING
💊 NULL값을 반환하는 Outer Join형태의 Scalar Subquery 예
-- Scalar Subquery는 일치하는 값이 없으면 NULL을 반환하므로 Outer Join과 같은 형태이다.
-- 아래는 부서별 최대 급여정보 조회 예이다.
-- 부서 40에 해당하는 직원이 없기 때문에 최대 급여가 조회 되지 않는다.
SELECT d.deptno, d.dname,
(SELECT MAX(sal)
FROM emp
WHERE deptno = d.deptno) sal
FROM dept d;
-- 결과가 동일한 Outer Join 예이다.
SELECT d.deptno, d.dname, MAX(e.sal)
FROM dept d, emp e
WHERE d.deptno = e.deptno(+)
GROUP BY d.deptno, d.dname
ORDER bY d.deptno;
DEPTNO DNAME SAL
------ ----------- -----
10 ACCOUNTING 5000
20 RESEARCH 3000
30 SALES 2850
40 OPERATIONS
728x90
반응형
'언어 > SQL' 카테고리의 다른 글
Equi Join, Non_Equi Join, Self Join (0) | 2022.06.14 |
---|---|
UNION, INTERSECT, MINUS 연산자 (0) | 2022.06.14 |
NVL, NVL2, NULLIF (0) | 2022.06.14 |
DECODE, CASE (0) | 2022.06.14 |
집계함수 (COUNT, MAX, MIN, AVG, SUM, STDDEV) (0) | 2022.06.14 |