DATABASE(oracleDB 11g)/SQL

[SQL]서브쿼리(SUBQUERY)의 종류

SEUNGSAMI 2019. 2. 8. 17:02

서브쿼리(SUBQUERY)의 종류



SUBQUERY 란 SQL명령문에 포함된 SELECT 명령문이다.

이때 서브쿼리는 메인쿼리보다 먼저 실행 될 수 있으며, 서브쿼리가 위치한 곳에 먼저 실행 될 수 있다.


다음은 서브쿼리를 분류한 것이다.


>> 반환 값에 따른 서브쿼리

 - Single row Subquery      : 서브쿼리 결과가 단일 행

  * 단일 행 비교 연산자에는 =, <, <=, > , >=, <>을 사용한다.


 - Multiple row Subquery    : 서브쿼리 결과가 여러 행

  * 다중 행 비교 연산자에는 IN, ALL, ANY, SOME, EXISTS가 있다.


함수명

설명 

IN

결과중 하나라도 일치하면 참

ANY,

SOME

결과와 하나 이상 일치하면 참

ALL

결과와 모든 값이 일치하면 참

EXISTS

결과 중에서 값이 있으면 참 메인쿼리 수행, 없으면 거짓으로 메인쿼리 수행안함



 - Multiple column Subquery : 서브쿼리 결과가 여러 컬럼

  * 메인쿼리의 조건절에 여러 컬럼을 동시에 비교가 가능하다.

  * 비교하고자 하는 컬럼 개수와 컬럼의 위치가 동일해야 한다.


>> Correlative Subquery(상관OR연관 서브쿼리)

 - 서브쿼리 내에 메인쿼리 컬럼이 사용된 서브 쿼리이다.

 - 실행 방식에 따른 구분 

 - 행 단위 처리를 위한 서브쿼리

 - 메인쿼리의 값을 서브쿼리가 사용하고, 서브쿼리의 값을 받아서 메인쿼리가 계산

 - 서브쿼리가 먼저 실행되지 못함

 - 실행되는 순서

1. 메인 쿼리가 먼저 실행

2. 후보행이 선택, 후보값이 서브쿼리 공급

3. 서브쿼리 실행, 겨과를 리턴

4. 리턴 받은 결과를 위치에 따라 사용 (출력, 조건비교 등)

5. 다음 후보행이 없을 때까지 2~4단계 반복

1
2
3
4
5
SELECT * 
FROM EMP E 
WHERE SAL > (SELECT AVG(SAL)
             FROM EMP 
             WHERE DEPTNO = E.DEPTNO); 
cs



>> Scalar Subquery(스칼라 서브쿼리)

 - 단일 column, row 리턴  

 - GROUP BY 절을 제외한 모든 절(COLUMN을 쓸 수있는 절)에서 사용 가능 

 - 반드시 하나의 결과만을 되돌려야 한다.


아래 예시들을 참고.

1
2
3
4
5
6
SELECT ENAME,
       (SELECT DNAME 
        FROM DEPT D 
        WHERE D.DEPTNO = E.DEPTNO) AS "DEPTNO"
FROM EMP E
WHERE JOB ='MANAGER';
cs



1
2
3
4
5
SELECT * 
FROM EMP 
WHERE SAL > (SELECT SAL 
             FROM EMP 
             WHERE EMPNO = 7788) ;
cs

다음의 쿼리를
1
2
3
SELECT E.EMPNO, E.ENAME, E.DEPTNO, D.DNAME
FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO;
cs

스칼라 서브쿼리를 이용해 다음과 같이 변경 가능하다.

1
2
3
4
5
SELECT EMPNO, ENAME, DEPTNO, 
      (SELECT DNAME 
       FROM DEPT D 
       WHERE E.DEPTNO = D.DEPTNO)
FROM EMP E;
cs

*데이터 건수가 적을경우 JOIN보다 유리하다.


>> 위치에 따른 Subquery의 분류

    - SELECT문에 있는 서브쿼리 : Scalar Subquery

    - FROM절에 있는 서브쿼리 : Inline View

    - WHERE절에 있는 서브쿼리 : Subquery


>조건절의 Subquery(WHERE, HAVING)

  - 리턴되는 ROW, COLUMN에 따라 비교 연산자를 주의 해야 한다.

  - ORDER BY에는 사용할 수 없다.

  - HAVING절에서는 그룹함수와 함께 사용될 때 그룹핑된 결과에 대해 부가적인 조건을 주기 위해서 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT * 
FROM EMP 
WHERE SAL IN (SELECT MIN(SAL) 
              FROM EMP 
              GROUP BY DEPTNO
              ORDER BY 1 );    -- ERROR 
 
 
 
SELECT DEPTNO, SUM(SAL) 
FROM EMP 
GROUP BY DEPTNO 
HAVING SUM(SAL) > (SELECT AVG(SUM(SAL))
                   FROM EMP 
                   GROUP BY DEPTNO) ;  
cs



>FROM절에서 사용되는 서브쿼리(Inline View)

 - Correlated Subquery 사용 불가능 하다.

 - ORDER BY 절에서는 사용 가능하다.

 - 둘이상의 ROW, COLUMN을 반환하는건 상관이 없다.

 - 필요한 테이블을 만들수 있는 결과식이 중요하다.

1
2
3
4
5
6
SELECT D.*, E.SUM_SAL 
FROM DEPT D 
JOIN (SELECT DEPTNO, SUM(SAL) AS SUM_SAL 
      FROM EMP 
      GROUP BY DEPTNO) E 
  ON D.DEPTNO = E.DEPTNO ; 
cs


1
2
3
4
5
SELECT * 
FROM (SELECT * 
      FROM EMP 
      ORDER BY SAL DESC) 
WHERE ROWNUM <= 3;
cs


>SELECT, ORDER BY 절 서브쿼리

 - Scalar Subquery 만 가능

 - SELECT절(Scalar Subquery)

 - 성능 저하가 주의 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT D.*
      ,(SELECT SUM(SAL)
        FROM EMP 
        WHERE DEPTNO = D.DEPTNO) AS SUM
FROM DEPT D; 
 
SELECT D.*
      ,(SELECT SUM(SAL)
        FROM EMP 
        WHERE DEPTNO = D.DEPTNO) AS SUM
      ,(SELECT AVG(SAL)
        FROM EMP 
        WHERE DEPTNO = D.DEPTNO) AS AVG
FROM DEPT D ;
--이러한 경우 JOIN을 쓰는게 더 효율적이다
cs


 - ORDER BY절

1
2
3
4
5
6
7
8
9
10
11
SELECT *
FROM DEPARTMENTS
ORDER BY DEPARTMENT_NAME;
 
SELECT *
FROM EMPLOYEES E 
ORDER BY (SELECT DEPARTMENT_NAME 
          FROM DEPARTMENTS 
          WHERE DEPARTMENT_ID = 
              E.DEPARTMENT_ID); 
--거의 쓰이지 않는다
cs




SQL을 배운지 얼마 되지 않아 잘못된 내용이 있을 수 있습니다. 틀린 내용이있다면, 댓글로 달아주세요.