01. 서브쿼리
- 하나의 SQL문안에 포함되어 있는 또 다른 SQL을 의미
- 반드시 괄호로 묶어야함
- 서브쿼리 사용 가능한 곳
- SELECT, FROM, WHERE, HAVING, ORDER BY, 기타 DML(INSERT, DELETE, UPDATE)
- GROUP BY 절만 제외하고 가능
02. 서브쿼리 종류
- 동작하는 방식에 따라
- UN-CORRELATED (비연관) 서브쿼리
- 서브쿼리가 메인쿼리 컬럼을 가지고 있지 않은 형태의 서브쿼리
- 사용: 메인쿼리에 서브쿼리가 실행된 결과 값을 제공하기 위한 목적
- CORRELATED (연관) 서브쿼리
- 서브쿼리가 메인쿼리 컬럼을 가지고 있는 형태의 서브쿼리
- 사용: (일반적)메인쿼리가 먼저 수행된 후에 서브쿼리에서 조건이 맞는지 확인하고자 할 때 사용
- UN-CORRELATED (비연관) 서브쿼리
- 위치에 따라
- 스칼라 서브쿼리
- 사용 위치: SELECT절
- 목적: 서브쿼리 결과를 마치 하나의 컬럼처럼 사용하기 위해
- 인라인뷰
- 사용 위치: FROM절
- 목적: 서브쿼리 결과를 테이블처럼 사용하기 위해
- WHERE절 서브쿼리
- 가장 일반적인 서브쿼리
- 목적: 비교 상수 가지에 값을 전달하기 위해, 상수항의 대체
- 리턴 데이터의 형태에 따라 단일행 서브쿼리, 다중행 서브쿼리, 다중컬럼 서브쿼리, 상호연관 서브쿼리로 구분
- 스칼라 서브쿼리
SELECT * | 컬럼명 | 표현식
, (SELECT * | 컬럼명 | 표현식
FROM 테이블명 | 뷰명
WHERE 조건)
FROM 테이블명 | 뷰명; --스칼라 서브쿼리
SELECT * | 컬럼명 | 표현식
FROM (SELECT * | 컬럼명 | 표현식
FROM 테이블명 | 뷰명)
WHERE 조건; --인라인뷰
SELECT * | 컬럼명 | 표현식
FROM 테이블명 | 뷰명
WHERE 조건연산자 (SELECT * | 컬럼명 | 표현식
FROM 테이블명 | 뷰명
WHERE 조건); --WHERE절 서브쿼리
03. WHERE절 서브쿼리 종류
- 단일행 서브쿼리
- 서브쿼리 결과: 1개
- 단일행 서브쿼리 연산자 종류: =, <>, >, >=, <, <=
- 다중행 서브쿼리
- 서브쿼리 결과: 여러 행
- 비교 연산자 사용 불가 (여러 값이랑 비교 할 수 없는 연산자들)
- 서브쿼리 결과를 하나로 요약하거나 다중행 서브쿼리 연산자를 사용
- 다중행 서브쿼리 연산자 종류
연산자 | 의미 | 예시 | 설명 |
IN() | 같은 값을 찾음 | IN(1, 2, 4, 5, 6, 10) | 1, 2, 4, 5, 6, 10 중에서 같은 값을 가지는 값을 반환 |
> ANY() | 최소 값을 찾음 | > ANY(100, 200) | 최소 값(100)보다 큰 행들을 반환 |
< ANY() | 최대 값을 찾음 | < ANY(100, 200) | 최대 값(200)보다 작은 행들을 반환 |
< ALL() | 최소 값을 찾음 | < ALL(100, 200) | 최소 값(100)보다 작은 행들을 반환 |
> ALL() | 최대 값을 찾음 | > ALL(100, 200) | 최대 값(200)보다 큰 행들을 반환 |
- ANY: 기호(> 또는 <)의 방향에 비례하게 최소/최대 값이 설정됨
- ALL: 기호(> 또는 <)의 방향에 반비례하게 최대/최소 값이 설정됨
SELECT empno, ename, sal
FROM emp
WHERE sal > (SELECT sal FROM emp
WHERE deptno = 10); --서브쿼리의 결과가 다중값인 경우, 연산자와 대소비교 불가
SELECT empno, ename, sal
FROM emp
WHERE sal > (SELECT MIN(sal) FROM emp
WHERE deptno = 10); --해결 1) 서브쿼리의 결과가 다중값인 경우, 하나의 행의 결과가 나오도록 변경
SELECT empno, ename, sal
FROM emp
WHERE sal > ANY(SELECT sal FROM emp
WHERE deptno = 10); --해결 2) 서브쿼리의 결과가 다중값인 경우, 다중행 서브쿼리 연산자로 변경
- 다중컬럼 서브쿼리
- 서브쿼리 결과가 여러 컬럼이 리턴되는 형태
- 메인쿼리와의 비교 컬럼이 2개 이상
- 대소 비교 전달 불가 (두 값을 동시에 묶어 대소비교할 수 없음)
SELECT empno, ename, sal, deptno
FROM emp
WHERE (deptno, sal) IN (SELECT deptno, MAX(sal) FROM emp
GROUP BY deptno); --부서별 최대 급여가 여러 값이 나옴, 비교시에는 다중행 연산자인 IN을 사용(= 사용 시 에러 발생)
- 상호연관 서브쿼리
- 메인쿼리와 서브쿼리의 비교를 수행하는 형태
- 비교할 집단이나 조건은 서브쿼리에 명시
- 메인쿼리에는 서브쿼리 컬럼이 정의되지 않았기 때문에 에러 발생
SELECT empno, ename, sal, deptno
FROM emp
WHERE (depno, sal) > (SELECT deptno, AVG(sal) FROM emp
GROUP BY deptno); --에러 발생: 다중 컬럼 서브쿼리는 동시 두 컬럼에 대한 대소비교 불가
SELECT empno, ename, sal, deptno
FROM emp e1
WHERE sal > (SELECT deptno, AVG(sal) FROM emp e2
WHERE e1.deptno = e2.deptno
GROUP BY deptno); --해결: 대소 비교할 컬럼을 메인쿼리에 일치 조건을 서브쿼리에 전달
04. 인라인뷰 (Inline View)
- 쿼리 안의 뷰의 형태
- 테이블처럼 조회할 데이터를 정의하기 위해 사용
- 테이블명이 존재하지 않음, 다른 테이블과 조인 시 반드시 테이블 별칭 명시
- 단독으로 사용: 필요 없음
- WHERE절 서브쿼리와 다르게 서브쿼리 결과를 메인쿼리 어느 절에서도 사용할 수 있음
- 사용: 인라인뷰의 결과와 메인쿼리 테이블과 조인할 목적
- 모든 연산자 사용 가능
SELECT e.ename, e.empno, e.sal, I.max_sal
FROM emp e, (SELECT deptno, MAX(sal) as max_sal FROM emp
GROUP BY deptno) I
WHERE e.deptno = I.deptno
AND e.sal = I.max_sal; --인라인뷰, 뷰의 형태로 테이블처럼 조회할 데이터를 정의하기 위해
05. 스칼라 서브쿼리
- SELECT절에서 사용하는 쿼리
- 마치 하나의 컬럼처럼 표현하기 위해 사용
- 단, 하나의 출력 대상만 표현 가능
- 각 행마다 스칼라 서브쿼리 결과가 하나여야 함 (단일행 서브쿼리)
- 조인의 대체 연산
- 스칼라 서브쿼리를 사용한 조인 처리: OUTER JOIN이 기본
- 값이 없더라도 생략되지 않고 NULL로 출력됨
SELECT empno, ename, (SELECT dname FROM dept D WHERE D.deptno = E.deptno) AS dname
FROM emp E
where deptno = 10; --스칼라 서브쿼리
SELECT E1.ename AS 사원명,
(SELECT E2.ename FROM emp E2
WHERE E1.mgr = E2.empno) AS 상위관리자명
FROM emp E1; --서브쿼리와 OUTER JOIN
06. 서브쿼리 주의사항
- 특별한 경우 (TOP-N 분석 등)을 제외하고는 서브쿼리절에 ORDER BY절 사용 불가
- 단일 행 서브쿼리와 다중 행 서브쿼리에 대한 연산자의 선택이 중요
SELECT *
FROM emp
WHERE sal IN (SELECT sal FROM emp WHERE deptno = 10
ORDER BY sal); --에러 발생: 서브쿼리에 ORDER BY 전달
'SQL' 카테고리의 다른 글
[SQL] 그룹 함수 (0) | 2025.02.17 |
---|---|
[SQL] 집합 연산자 (0) | 2025.02.17 |
[SQL] JOIN (2) (0) | 2025.02.17 |
[SQL] JOIN (1) (0) | 2025.02.14 |
[SQL] ORDER BY 절 (0) | 2025.02.14 |