본문 바로가기
CS/DB

서브쿼리(Subquery)란

by Ropung 2023. 10. 15.

✔️서브쿼리(Subquery)에 대해서 알아보자.

데이터 조회를 하다보면, 잦은 빈도로 서브쿼리를 사용하게 된다고 한다.
보통 서브쿼리는 실행 속도가 느려서 잘 안쓰는 것으로 막연하게 알고있어서 정리가 필요하다고 느꼈다.


✔️서브쿼리(Subquery)개념잡기

개념

  • 서브쿼리는 하나의 SQL문 내에 괄호()로 감싸져서 표현되어 있는 또 다른 SQL문을 말한다.

  • 서브쿼리를 포함하고 있는 쿼리를 외부쿼리(outer query)라고 부르며, 서브쿼리는 내부쿼리(inner query)라고 부른다.

  • SQL 내부에서 작성되는 일시적인 테이블인데, 여기서 '일시적인 테이블’이라는 부분이 성능적인 차이를 불러온다.

구분 설명 특징
테이블(Table) DB에 물리적으로 저장된 데이터(영속적) 영속적
뷰(View) 가상의 테이블, 접근할 때 마다 SELECT 구문이 실행됨 영속적, 물리적 저장 X
서브쿼리(Subquery) 가상의 테이블, SQL 구문 실행 중에만 존재 일시적, 물리적 저장 X
  • 세가지 모두 데이터를 저장하고 있는 테이블로써 활용한다는 공통점이 있다.

서브쿼리의 실행 순서

  • 서브쿼리가 먼저 실행된 후 메인(부모) 쿼리가 실행된다.
  • ORDER BY를 사용 할 수 없다.
-- 메인쿼리 영역  <- 서브쿼리가 실행된 후 실행
select * 
from my_table
where target_id in (
-- (서브쿼리 영역 )  <- 먼저 실행
	select id
	from sub_table_noindex_51
	where id < 50
)
  • 서브쿼리는 하나의 SQL 문 안에 포함되어 있는 또 다른 SQL 문을 말한다.
  • (select id from sub …) 같이 괄호()안에 있는 쿼리를 서브 쿼리라고 말한다.

Java의 상속과 비슷한 개념

  • 서브쿼리는 메인쿼리의 컬럼을 사용할 수 있고, 메인쿼리는 서브쿼리의 컬럼을 사용할 수 없다.
  • 상속당한 자식 객체는 부모 객체의 인스턴스를 사용할 수 있고, 부모는 자식객체의 인스턴스를 사용할 수 없다.

서브 쿼리의 장점을 알아보자.

  • 쿼리를 구조화시키므로, 쿼리의 각 부분을 명확히 구분할 수 있게 해준다.
  • 복잡한 JOIN이나 UNION과 같은 동작을 수행할 수 있는 또 다른 방법을 제공한다.
  • 복잡한 JOIN이나 UNION 보다 좀 더 읽기 편해서 가독성이 좋다.

✔️서브쿼리 위치에 따른 명칭

  • 서브쿼리는 위치에 따라 명칭이 다르다.
  • 주관적으로 왜 탑 미들 바텀 같은 직관적이지 않은, 스칼라 인라인 WHERE 절에 붙는 일반 서브쿼리라고 하는지 도통 이해가 안된다.
SELECT col1, (SELECT ...) -- 스칼라 서브쿼리(Scalar Sub Query)
FROM (SELECT ...)         -- 인라인 뷰(Inline View)
WHERE col = (SELECT ...)  -- 일반 서브쿼리

스칼라 서브쿼리(Scalar Sub Query)

  • 스칼라(scalar) 는 ‘한번에 한가지만 처리하는’ 이라는 뜻을 가지고 있다.
  • SELECT문 위치에 쓰이는 서브쿼리
  • 이름 그대로 하나의 레코드만 리턴이 가능하며, 두개 이상의 레코드는 리턴할 수 없다.
  • 다른 테이블에서 어떠한 값을 가져올 때 쓰인다.
  • 일치하는 데이터가 없더라도 NULL값을 리턴할 수 있다. 이는 그룹함수의 특징중에 하나인데 스칼라 서브쿼리 또한 이러한 특징을 가지고 있다고 한다.

인라인 뷰(Inline View)

  • 인라인 뷰는 별도의 객체 없이 직접 코드에 적었다라는 뜻을 가졌다고 한다.
  • FROM문 위치에 쓰이는 서브쿼리
  • 서브쿼리가 FROM절에 사용 될 경우 무조건 AS(별칭)을 지정해 주어야 한다.

중첩 서브쿼리(Nested Subquery)

  • WHERE문 위치에 쓰이는 일반 서브쿼리
-- 조건값을 상수로 할 때
select name,height
from userTb
where heigjt > 178;

-- 조건값을 select로 특정할 때 (단 결과가 값이 하나여야됨)
select name, height
from userTb
where height > (select height from userTb where name in ('이름'));

-- 조건에 값이 여러개 들어올땐 any.
-- any는 in과 동일한 의미. or을 의미한다.
select name, height
from userTb
where height = any(select height from userTb where addr in ('주소'));

-- all은 도출된 모든 조건값에 대해 만족할 때. and를 의미
select *
from city
where population > all(select population from city where district = '뉴욕');

서브쿼리 사용 가능 한 곳

MySQL에서 서브쿼리를 포함할 수 있는 외부쿼리는 SELECT, INSERT, UPDATE, DELETE, SET, DO 문이 있다.

  • SELECT
  • FROM
  • WHERE
  • HAVING
  • ORDER BY
  • INSERT문의 VALUES 부분 대체제
  • UPDATE문의 SET 부분 대체제

✔️서브쿼리 예제

회사원 정보 테이블

CREATE TABLE employee (
	id INT AUTO_INCREMENT PRIMARY KEY,
	이름 VARCHAR(), 
	연봉 INT, 
	직급 VARCHAR(64) 
) 
INSERT INTO employee VALUES(1,'허사장',20000000,'사장');
INSERT INTO 
	employee (이름,연봉,직급) 
	VALUES
	('유부장',10000000,'부장'),
	('박차장',5000000,'차장'),
	('정과장',4000000,'과장'),
	('정대리',3895000,'대리'), 
	('노사원',2500000,'사원'), 
	('하사원',2000000,'사원'), 
	('길인턴',1000000,'인턴');

스칼라 서브쿼리(Scalar Subquery)

-- 스칼라 서브쿼리(Scalar Subquery) 
-- 정대리 급여와 테이블 전체 평균 급여를 구하시오.
SELECT 이름,연봉,(
	SELECT ROUND(AVG(연봉),-1)
	FROM employee) AS '평균급여'
FROM employee
WHERE 이름 = '정대리';

인라인 뷰 (Inline View)

-- 꼭 파생 테이블엔 as(별칭)을 정해줘야 한다.
SELECT * FROM(SELECT * FROM employee WHERE 직급 = '사원') --(X)

-- 직급이 사원인 사람들의 이름과 급여를 구하시오.
SELECT e.이름, e.연봉
FROM (
	SELECT *
	FROM employee AS 고용
	WHERE 고용.직급 = '사원' e;
);

중첩 서브쿼리 - 단일 행

-- 정대리라는 사람의 직급을 구하시오.
SELECT 직급 
FROM employee 
WHERE 직급 = (SELECT 직급 FROM employee WHERE 이름 = '정대리');

중첩 서브쿼리 - 복수(다중) 행

  • IN, ANY, ALL, EXISTS 등의 연산자로 얻은 서브쿼리 결과 여러개의 행을 반환.
-- 정대리보다 급여가 높은 사람들을 구하시오.
SELECT * FROM employee 
WHERE 연봉 > ( SELECT 연봉 FROM employee WHERE 이름 = '정대리' )

-- 직급이 사원인 사람들을 구하시오.
SELECT * FROM employee
WHERE 직급 IN(
	SELECT 직급
	FROM employee
	WHERE 직급 = '사원'
);

INSERT문 서브쿼리

-- 테이블 2의 정보를 뽑아서 그 데이터를 테이블 1에 넣어준다.
-- value()에 들어갈 자리를 서브쿼리로 대체 가능하다.
INSERT INTO table1 (SELECT * FROM table2)

DELETE문 서브쿼리

-- 인턴의 정보를 구해와서 삭제한다.
DELETE FROM employee
WHERE id = (SELECT id FROM employee where 직급 = '인턴');

UPDATE문 서브쿼리

-- 인턴에 정보를 구해와서 급여를 10만원 인상한다.
UPDATE employee SET 연봉=(연봉+10000)
WHERE id = (SELECT id FROM employee where 연봉 = '인턴')

✔️참고자료

서브쿼리 쓰기 싫어서 찾아본 블로그
서브 쿼리 정리
서브쿼리란 무엇인가
JPA에서 서브쿼리
스택오버플로우 Join vs Subquery
성능 관점에서의 서브쿼리
서브쿼리 총 정리

'CS > DB' 카테고리의 다른 글

SQL JOIN  (0) 2023.10.15
트랜잭션에 대해 알아보자  (3) 2023.09.15
DB, DBMS, SQL에 대해 알아보자  (0) 2023.09.12