내가 한 노력들

[DB] 서브쿼리 (단일행, 다중행, 다중열, WITH절) 본문

IT 공부/DB

[DB] 서브쿼리 (단일행, 다중행, 다중열, WITH절)

JONGI-N CHOI 2021. 12. 1. 12:00

서브쿼리

SQL문을 실행할 때, 추가로 필요한 데이터를 조회할 때 사용합니다. 

보통은 WHERE문에서 사용되지만, FROM, SELECT문 등에서도 사용이 가능합니다.

 

사용방법

SELECT 열
FROM 테이블
WHERE 조건식 (SELECT 열 FROM 테이블 WHERE 조건식);

 

예를 들어서, 학생 테이블에서 홍길동 학생의 학비보다 더 많이 학비를 내고 있는 학생들의 목록을 출력하고 싶을 경우에는 어떻게 해야하나?

 

홍길동 학생의 학비값을 출력해서 얻은 다음 -> 그 값을 WHERE 조건식에 넣어서 조건식에 만족하는 학생들 출력

SELECT 학비
FROM 학생
WHERE 이름 = '홍길동';

 

위의 출력값이 300이었을 때,

SELECT *
FROM 학생
WHERE 학비 = 300;

두 번의 과정을 거쳐야 합니다.

 

하지만, 서브쿼리를 이요하면 하나의 쿼리문으로 작성하는 것이 가능합니다. 

 

SELECT *
FROM 학생
WHERE 학비 > (SELECT 학비 FROM 학생 WHERE 이름 = '홍길도');

 

주의할점

1. 서브쿼리는 조회 대상의 오른쪽에 위치하며, 괄호로 묶어서 사용합니다.

2. 조건식에 있는 값과 서브쿼리의 결과 값이 같은 자료형과 같은 개수로 지정해야 한다.

3. 서브쿼리 결과의 수가 다중행인지 단일행인지에 맞춰서 조건식을 지정해야 한다. 


단일행 서브쿼리

서브쿼리의 실행 결과가 하나의 행으로 나오는 서브쿼리를 단일행 서브쿼리라고 합니다. 

단일행 서브쿼리는 단일행 연산자를 사용해야 합니다.

 

단일행 연산자의 종류

> : 초과

>= : 이상

< : 미만

<= : 이하

= : 동일

!= ( = <> = ^=) : 다름

 


다중행 서브쿼리

실행 결과 행이 두 개이상으로 출력되는 경우를 다중행 서브쿼리라고 합니다.

다중행 서브쿼리는 다중행 연산자를 사용해야 합니다.

 

 

다중행 연산자의 종류

IN : 메인쿼리의 데이터가 서브쿼리의 결과 중 하나라도 일치한 데이터가 있으면 TRUE

ANY, SOME : 메인쿼리의 조건식을 만족하는 서브쿼리의 결과가 하나 이상이면 TRUE

ALL : 메인쿼리의 조건식을 서브쿼리의 결과 모두 만족한다면 TRUE

EXISTS : 서브쿼리의 결과가 1개라도 존재하면 TRUE

 

 

IN

SELECT *
FROM 학생
WHERE 학비 (SELECT MAX(학비) FROM 학생 GROUP BY 학과);

학과별로 학생들의 최고 학비값이 서브쿼리 결과값에 출력이 됩니다. (다중행 서브쿼리)

그 결과값들중에서 메인쿼리에서의 출력값중 일치하는 값이 있으면 출력이 됩니다. 


ANY

ANY는 조건식에 서브쿼리 결과값중 하나라도 만족하면 TRUE입니다. 

ANY를 사용할 때에는 조건식에 무엇을 사용하는지에 따라서 결과값이 달라진다. 

 

=

SELECT *
FROM 학생
WHERE 학비 = ANY (SELECT MAX(학비) FROM 학생 GROUP BY 학과);

=과 ANY를 같이 사용하는 경우에는 IN을 사용했을 때와 결과값이 똑같습니다. 

 

<

SELECT *
FROM 학생
WHERE 학비 < ANY (SELECT MAX(학비) FROM 학생 GROUP BY 학과);

서브쿼리의 결과값이 200, 300, 400일 경우

ANY는 하나라도 만족하면 TRUE이기 때문에 결국엔 400보다 작기만 하면, 무조건 TRUE라는 소리와 같습니다.

 

>

SELECT *
FROM 학생
WHERE 학비 > ANY (SELECT MAX(학비) FROM 학생 GROUP BY 학과);

서브쿼리의 결과값이 200, 300, 400일 경우

ANY는 하나라도 만족하면 TRUE이기 때문에 결국엔 200보다 크면, 무조건 TRUE라는 소리와 같습니다.


ALL

ALL는 조건식에 서브쿼리 결과값을 모두 만족해야 TRUE

 

 

<

SELECT *
FROM 학생
WHERE 학비 < ALL (SELECT MAX(학비) FROM 학생 GROUP BY 학과);

서브쿼리의 결과값이 200, 300, 400일 경우

ALL은 모든 조건을 만족해야 TRUE이기 때문에 결국엔 200보다 작아야지 TRUE

 


>

SELECT *
FROM 학생
WHERE 학비 > ALL (SELECT MAX(학비) FROM 학생 GROUP BY 학과);

서브쿼리의 결과값이 200, 300, 400일 경우

ALL은 모든 조건을 만족해야 TRUE이기 때문에 결국엔 400보다 커야지 TRUE

 


EXISTS

서브쿼리에 결과 값이 하나라도 존재하면 조건식이 모두 TRUE가 됩니다. 

 

SELECT *
FROM 학생
WHERE EXISTS (SELECT 이름 FROM 학생 WHERE 학번 = 1234);

위의 코드는, 학번 1234인 학생이 존재하는 경우에는 학생 테이블의 모든 행을 출력시켜라 라는 것과 같은 의미입니다.

 

특정 서브쿼리 결과 값의 존재 유무를 통해 메인쿼리 데이터를 노출할지를 결정할 때 사용합니다. 

 


다중열 서브쿼리

서브쿼리의 SELECT절에 비교할 데이터를 여러개 지정할 때 사용합니다. 

메인쿼리에 비교할 열을 괄호로 묶어 명시합니다. 

SELECT *
FROM 학생
WHERE (학번, 학비) IN (SELECT 학번, MAX(학비) FROM 학생 GROUP BY 학과);

 


FROM절에 사용하는 서브쿼리와 WITH절 

서브쿼리는 FROM절에도 사용이 가능합니다.

 

SELECT SM.학번, SM.이름, M.학과, M.학비
FROM (SELECT * FROM 학생 WHERE 학과번호 = 310) SM,
	 (SELECT * FROM 학과) M
WHERE SM.학과번호 = M.학과번호;

FROM절에 서브쿼리를 사용하는 이유는 테이블의 규모가 너무 큰 경우나 필요한 열만 사용하고자 하는 경우에 사용합니다. 

 

근데 위와 같은 쿼리문은 너무 가독성이 떨어지기 때문에 WITH절을 이용해서 깔끔하게 바꿀 수 있다. 

 

WITH
SM AS (SELECT * FROM 학생 WHERE 학과번호 = 310),
M AS (SELECT * FROM 학과) 
SELECT SM.학번, SM.이름, M.학과, M.학비
FROM SM, M	 
WHERE SM.학과번호 = M.학과번호;

SELECT절에 사용하는 서브쿼리

SELECT절에 사용하는 서브쿼리를 스칼라 서브쿼리라고도 한다. 

 

SELECT 학번, 이름, (SELECT 성적 FROM 성적표 WHERE 학생.점수 BETWEEN 60 AND 70) AS GRADE
FROM 학생;