1. Subquery

- SQL문을 실행하는데 필요한 데이터를 추가로 조회하기 위해 SQL문 내부에서 사용하는 SELECT문을 의미한다.

- 반대로, 서브쿼리의 결과 값을 사용하여 기능을 수행하는 영역은 Main query라고 부른다.

 

1.1 특징

- 서브쿼리는 연산자와 같은 비교 또는 조회 대상의 오른쪽에 놓이며 괄호 ()로 묶어서 사용한다.

- 특수한 몇몇 경우를 제외한 대부분의 서브쿼리에서는 ORDER BY절을 사용할 수 없다.

- 서브쿼리의 SELECT절에 명시한 컬럼은 메인쿼리의 비교 대상과 같은 자료형과 같은 개수로 지정해야 한다.

- 서브쿼리에 있는 SELECT문의 결과 행 수는 함께 사용하는 메인쿼리의 연산자 종류와 호환 가능해야 한다.

 

2. 단일행 서브쿼리

- 실행 결과가 단 하나의 행으로 나오는 서브쿼리를 의미한다.

- 서브쿼리에서 출력되는 결과가 하나이므로 메인쿼리와 서브쿼리 결과는 단일행 연산자(<, <=, >, >=, =, <>, ^=, !=)를 사용하여 비교한다.

/* 예시1 */
SELECT *
FROM EMP
WHERE HIREDATE < (SELECT HIREDATE FROM EMP WHERE ENAME='SCOTT');

/* 예시2 */
SELECT E.EMPNO, E.ENAME, E.SAL, D.DEPTNO, D.DNAME
FROM EMP E, DEPT D
WHERE E.DEPTNO=D.DEPTNO
AND E.DEPTNO=20
AND E.SAL > (SELECT AVG(SAL) FROM EMP);

 

3. 다중행 서브쿼리

- 실행 결과 행이 여러 개로 나오는 서브쿼리를 의미한다. 그렇기 때문에 단일행 연산자는 사용할 수 없고 다중행 연산자를 사용해야 메인쿼리와 비교할 수 있다.

- 다중행 연산자 종류

종류 설명 및 예시
IN - 메인쿼리의 데이터가 서브쿼리의 결과 중 하나라도 일치한 데이터가 있다면 TRUE
- SELECT * FROM EMP WHERE SAL IN (SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO);
ANY, SOME - 메인쿼리의 조건식을 만족하는 서브쿼리의 결과가 하나 이상이면 TRUE
- SELECT * FROM EMP
WHERE SAL < ANY (SELECT SAL FROM EMP WHERE DEPTNO=30)
ORDER BY SAL, EMPNO;
- SELECT * FROM EMP WHERE SAL = SOME (SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO);
ALL - 메인쿼리의 조건식을 서브쿼리의 결과 모두가 만족하면 TRUE
- SELECT * FROM EMP WHERE SAL < ALL (SELECT FROM EMP WHERE DEPTNO = 30);
EXISTS - 서브쿼리의 결과가 존재(행이 1개 이상일 경우)하면 TRUE, 존재하지 않으면 FALSE가 된다.
- FALSE 조건의 서브쿼리를 실행하면 결과 데이터에 아무 행도 출력되지 않는다.
- SELECT * FROM EMP WHERE EXISTS (SELECT DNAME FROM DEPT WHERE DEPTNO = 50);

 

3.1 서브쿼리에 ANY, SOME 연산자를 사용한 경우와 IN 연산자를 사용한 경우 비교

- 메인쿼리와 값을 비교할 때 ANY 및 SOME 연산자를 등가 비교 연산자(=)와 함께 사용하면 IN 연산자와 정확히 같은 기능을 수행한다.

- IN 연산자가 알아보기도 편하고 글자 수도 적기 때문에 IN 연산자 사용이 더 선호되는 편이다.

/* ANY 연산자 + 등가 비교 연산자(=) */
SELECT *
FROM EMP
WHERE SAL = ANY (SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO);

/* IN 연산자 */
SELECT *
FROM EMP
WHERE SAL IN (SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO);

/* 같은 결과가 나온다. */

 

3.2 서브쿼리에 ANY, SOME 연산자를 사용한 경우와 MAX, MIN 함수를 사용한 경우 비교

/* < ANY 연산자 */
SELECT *
FROM EMP
WHERE SAL < ANY (SELECT SAL FROM EMP WHERE DEPTNO=30)
ORDER BY SAL, EMPNO;

/* MAX 함수 */
SELECT *
FROM EMP
WHERE SAL < (SELECT MAX(SAL) FROM EMP WHERE DEPTNO=30)
ORDER BY SAL, EMPNO;

/* 같은 결과가 나온다. */

 

4. 다중열 서브쿼리

- 서브쿼리의 SELECT절에 비교할 데이터를 여러 개 지정하는 방식이다.

- 메인쿼리에 비교할 열을 괄호로 묶어 명시하고 서브쿼리에서는 괄호로 묶은 데이터와 같은 자료형 데이터를 SELECT절에 명시하여 사용한다.

/* 예시 */
SELECT *
FROM EMP
WHERE (DEPTNO, SAL) IN (SELECT DEPTNO, MAX(SAL) FROM EMP GROUP BY DEPTNO);

 

5. Inline View

- FROM절에서 사용하는 서브쿼리를 의미한다.

- 특정 테이블 전체 데이터가 아닌 SELECT문을 통해 일부 데이터를 먼저 추출해 온 후 별칭을 주어 사용한다.

- FROM절에 직접 테이블을 명시하여 사용하기에는 테이블 내 데이터 규모가 너무 크거나 현재 작업에 불필요한 열이 너무 많아 일부 행과 열만 사용하고자 할 때 유용하다.

- 하지만 FROM절에 너무 많은 서브쿼리를 지정하면 가독성이나 성능이 떨어질 수 있다.

/* 예시 */
SELECT E10.EMPNO, E10.ENAME, E10.DEPTNO, D.DNAME, D.LOC
FROM (SELECT * FROM EMP WHERE DEPTNO=10) E10, (SELECT * FROM DEPT) D
WHERE E10.DEPTNO=D.DEPTNO;

 

5.1 WITH절

WITH
[별칭1] AS (SELECT문1),
[별칭2] AS (SELECT문2),
...
[별칭n] AS (SELECT문n)

- 오라클 9i부터 제공한다.

- 인라인 뷰에서 FROM절에 너무 많은 서브쿼리가 지정되어 가독성이나 성능이 떨어지는 것을 방지하기 위해 사용한다.

- 메인쿼리가 될 SELECT문 안에서 사용할 서브쿼리와 별칭을 먼저 지정한 후 메인쿼리에서 사용한다.

/* 예시 */
WITH
E10 AS (SELECT * FROM EMP WHERE DEPTNO=10),
D AS (SELECT * FROM DEPT)
SELECT E10.EMPNO, E10.ENAME, E10.DEPTNO, D.DNAME, D.LOC
FROM E10, D
WHERE E10.DEPTNO=D.DEPTNO;

 

6. Correlated Subquery

- 상호 연관 서브쿼리라고 불린다.

- 메인쿼리에 사용한 데이터를 서브쿼리에서 사용하고 서브쿼리의 결과 값을 다시 메인쿼리로 돌려주는 방식이다.

- 성능을 떨어뜨리는 원인이 될 수 있어 사용 빈도가 높지는 않다.

/* 예시 */
SELECT *
FROM EMP E1
WHERE SAL > (SELECT MIN(SAL) FROM EMP E2 WHERE E2.DEPTNO=E1.DEPTNO)
ORDER BY DEPTNO, SAL;

 

7. Scalar Subquery

- 스칼라 서브쿼리라고 불린다.

- SELECT절에 하나의 열 영역으로서 결과를 출력할 수 있다.

- SELECT절에 명시하는 서브쿼리는 반드시 하나의 결과만 반환하도록 작성해야 한다.

/* 예시 */
SELECT EMPNO, ENAME, JOB, SAL,
	(SELECT GRADE FROM SALGRADE WHERE E.SAL BETWEEN LOSAL AND HISAL) AS SALGRADE,
	DEPTNO,
	(SELECT DNAME FROM DEPT WHERE E.DEPTNO=DEPT.DEPTNO) AS DNAME
FROM EMP E;

 

참고

- 『오라클로 배우는 데이터베이스 입문』

'Database' 카테고리의 다른 글

DML(Data Manipulation Language)  (0) 2021.10.21
Oracle 테이블 및 데이터 복사  (0) 2021.10.21
JOIN 종류  (0) 2021.10.18
Oracle 그룹화 함수  (0) 2021.10.15
Oracle 다중행 함수  (0) 2021.10.15