나의 개발일지

[SQL] 서브 쿼리 본문

Oracle SQL

[SQL] 서브 쿼리

YoonJuHan 2023. 4. 24. 22:30

서브 쿼리와 메인 쿼리

  1. 메인 쿼리 (외부 쿼리)
    1. 결과를 반환할 때 사용할 최종 쿼리문
  2. 서브 쿼리 (내부 쿼리)
    1. SQL 문 내부에 포함되는 괄호 안의 쿼리문
    2. 중첩 SELECT 문 또는 하위 SELECT 문
    3. 외부 쿼리 (메인 쿼리)에 사용될 값만 처리
    4. 서브 쿼리 결과는 화면에 반환되지 않음
    5. 특별한 경우를 제외하고는 서브 쿼리는 메인 쿼리보다 먼저, 한 번만 실행

서브 쿼리가 필요한 경우

  1. 두 개의 순차적인 쿼리를 수행하여 첫 번째 쿼리 결과를 두 번째 쿼리의 검색 값으로 사용하는 경우와 동일한 작업을 하나의 SQL에서 실행
  2. 예시) 오상우 사원보다 급여가 많은 사원을 구하기 위해 먼저 오상우 사원의 급여를 구한다. (630)
  3.           그다음 오상우 사원의 급여인 630을 가지고 조건을 검색하는 쿼리를 또 작성한다. 이렇게 총 두 번의 쿼리 실행
  4. 두 번 해야하는 쿼리를 서브 쿼리를 사용해 한 번에 끝낼 수 있다.

서브 쿼리의 실행

  1. 조건 값을 알 수 없는 SQL 문을 작성하는데 매우 유용
  2. 주로 WHERE과 HAVING 절에서 연산자의 오른쪽에 많이 사용
  3. SQL 문장에서 서브쿼리가 사용될 수 있는 경우
    1. WHERE 절
    2. HAVING 절
    3. FROM 절
    4. OREDR BY 절

서브 쿼리의 구문

  1. 서브 쿼리는 괄호로 묶어야 하며 일반적으로 비교조건의 오른쪽에 위치
  2. 한 개의 메인 쿼리에 여러 개의 서브 쿼리가 존재 가능
  3. 구문
SELCET select_list
FROM table
WHERE 표현식 연산자 (SELECT select_list
		    FROM table);

 

  • 오상우 사원보다 급여를 많이 받는 직원의 이름과 직위, 급여를 표시
    • WHERE  조건은 salary > 630과 같은 의미가 된다.
SELECT emp_name, position, salary
FROM y_emp
WHERE salary > (SELECT salary FROM y_emp
                WHERE emp_name = '오상우');

서브 쿼리의 종류

  1. 반환되는 행의 수 기준
    1. 단일 행 서브 쿼리
    2. 다중 행 서브 쿼리
  2. 다중 열 서브 쿼리
  3. 인라인 뷰
    1. FROM 절에 사용된 서브 쿼리
  4. 스칼라 서브 쿼리
    1. 하나의 단일 값을 나타내기 위해 SELECT LIST, WHERE 절, ORDER BY 절, DML 등에 사용하는 서브 쿼리
  5. 상호 관련 서브 쿼리
    1. 메인 쿼리와 서브 쿼리의 특정 열 값을 상호비교

 

단일 행 서브 쿼리와 다중 행 서브 쿼리

  1. 서브 쿼리에서 반환되는 행 수에 의해 구분
    1. 서브 쿼리로부터 단일 행을 반환 : 단일 행 서브 쿼리
    2. 서브 쿼리로부터 여러 행을 반환 : 다중 행 서브 쿼리
  2. 서브 쿼리에서 사용될 비교 연산자를 구분하여 사용
    1. 단일 행 연산자 (>, =, >=, <, <>, <=)
    2. 여러 행 연산자 (IN, ANY, ALL)

 

단일 행 서브 쿼리

  1. 내부 SELECT 문 (서브 쿼리) 에서 하나의 행을 반환하는 서브 쿼리
  2. 단일 행 비교 연산자를 이용
  3. 사용 가능한 단일 행 비교 연산자
    1. =, >, >=, <, <=, <>

 

  • 1049번 사원과 직급이 동일한 사원을 표시
    •  WHERE position = '과장' 과 같은 의미
SELECT emp_name, position
FROM y_emp
WHERE position = (SELECT position FROM y_emp
                  WHERE emp_id = 1049);

 

  • 1044번 사원과 업무가 동일하면서 1050번 사원보다 급여를 많이 받는 사원을 반환하기 위한 구문
SELECT emp_name, position, salary FROM y_emp
WHERE position = (SELECT position FROM y_emp
                  WHERE emp_id = 1044)
AND salary > (SELECT salary FROM y_emp
              WHERE emp_id = 1050);

 

  • 서브 쿼리의 MIN 그룹 함수를 사용하여 회사에서 가장 적은 급여를 받는 사원에 대한 정보가 출력
SELECT emp_id, emp_name, position, salary
FROM y_emp
WHERE salary = (SELECT MIN(salary) 
                FROM y_emp);

 

  • HAVING 절에 서브 쿼리를 사용하여 회사의 업무 중 평균 급여가 가장 낮은 직급과 그 평균 급여를 반환
SELECT position, AVG(salary)
FROM y_emp
GROUP BY position
HAVING AVG(salary) = (SELECT MIN(AVG(salary)) FROM y_emp
                      GROUP BY position);

 

서브 쿼리에서 발생할 수 있는 문제

  1. 연산자의 잘못된 사용
    1. 단일 행 비교 연산자를 사용하면서 서브 쿼리에서는 여러 행을 반환하는 경우
    2. 쿼리의 구조를 변경하거나 연산자의 종류 변경
  2. 내부 쿼리에서 행을 반환하지 않는 경우
    1. 이 경우 서브 쿼리는 NULL 값을 반환하고 메인 쿼리는 서브 쿼리의 결과(NULL)를 받아 WHERE 절에서 사용
    2. 결과로 아무 행이 반환되지 않음
  3. 잘못 작성된 서브 쿼리 사용자가 잘못된 데이터를 최종 결과로 사용
  • 오류 예시)  직급이 차장인 사원과 급여가 같은 사원을 찾는 문장에서 서브 쿼리가 여러 행을 반환해 다일행 서브쿼리인 메인 쿼리가 오류를 반환
SELECT emp_id, emp_name, position, salary
FROM y_emp
WHERE salary = (SELECT salary FROM y_emp
                WHERE position = '차장');

 

다중 행 서브 쿼리

  1. 여러 행을 반환하는 서브 쿼리
  2. 여러 값을 처리하는 다중 행 연산자를 사용
  3. 다중 행 연산자의 종류
    1. IN : 목록의 임의의 값과 동등 비교
    2. ANY : 값을 서브 쿼리에 의해 반환된 각 값과 비교
    3. ALL : 값을 서브 쿼리에 의해 반환된 모든 값과 비교

 

  • 200번 이하의 부서에 대하여 각 부서의 최고 급여를 구한 후 그 급여와 동일한 급여를 받는 사원정보를 반환
SELECT emp_name, salary, dept_id
FROM y_emp
WHERE salary IN (SELECT MAX(salary)
                 FROM y_emp
                 WHERE dept_id <= 200
                 GROUP BY dept_id);

 

  • 직책이 대리가 아니면서 급여가 임의의 대리인 사원보다 낮은 사원을 표시
    • 대리 급여의 최댓값인 570보다 낮으면 모두 나옴 (모든 대리들의 급여들 보다 낮기만 하면 되기 때문에)
SELECT emp_id, emp_name, position, salary
FROM y_emp
WHERE salary < ANY
                   (SELECT salary FROM y_emp
                    WHERE position = '대리')
AND position <> '대리';

 

  • 직책이 대리가 아니면서 급여가 임의의 대리인 사원보다 높은 사원을 표시
    • 대리 급여의 최솟값인 350보다 높으면 모두 나옴 (모든 대리들의 급여들 보다 높기만 하면 되기 때문에)
SELECT emp_id, emp_name, position, salary
FROM y_emp
WHERE salary > ANY
                   (SELECT salary FROM y_emp
                    WHERE position = '대리')
AND position <> '대리';

 

  • 직책이 대리가 아니면서 급여가 대리 중 가장 낮은 사람 보다 낮은 사원을 표시
    • 대리 급여의 최솟값인 350보다 낮으면 모두 나옴 (모든 대리들의 급여들과 비교해서 낮아야 하기 때문에)
SELECT emp_id, emp_name, position, salary
FROM y_emp
WHERE salary < ALL
                  (SELECT salary FROM y_emp
                   WHERE position = '대리')
AND position <> '대리';

 

다중 열 서브 쿼리

To Be Continue..

 

 

Comments