-
서브쿼리(Subquery)를 알아보자MySQL 2023. 6. 3. 03:26
들어가기 전에
데이터베이스에 저장된 데이터를 가져올 때 조인(JOIN) 을 자주 사용하는데 서브쿼리와의 차이가 무엇인지 궁금해 알아보려고한다.
서브쿼리
서브쿼리(subquery)란 다른 쿼리 내부에 포함되어 있는 SELECT 문을 의미한다.
서브쿼리를 포함하고 있는 쿼리를 외부쿼리(outer query)라고 부르며, 서브쿼리는 내부쿼리(inner query)라고 부른다.
서브쿼리는 괄호() 로 감싸져서 표현된다.
서브쿼리 실행 → 메인(부모) 쿼리 실행
select * from main_table # 메인쿼리 where target_id in ( # 서브쿼리 select id from sub_table where id < 500 );- 서브쿼리는 하나의 SQL 문 안에 포함되어 있는 또 다른 SQL 문을 말한다.
- 괄호() 안에 있는 쿼리를 서브쿼리라 말한다.
- 서브쿼리(=자식쿼리, 내부쿼리)
: 메인쿼리 컬럼 사용 가능 - 메인쿼리(=부모쿼리, 외부쿼리)
: 서브쿼리 컬럼 사용 불가

서브쿼리 장점
- 서브쿼리는 쿼리를 구조화시키므로, 쿼리의 각 부분을 명확히 구분할 수 있게 해준다.
- 서브쿼리는 복잡한 JOIN 이나 UNION 과 같은 동작을 수행할 수 있는 또 다른 방법을 제공
- 서브쿼리는 복잡한 JOIN 이나 UNION 보다 좀 더 읽기 편함 (가독성이 좋음)
SELECT col1, (SELECT ...) # 스칼라 서브쿼리(Scalar Sub Query): 하나의 컬럼처럼 사용 (표현 용도) FROM (SELECT ...) # 인라인 뷰(Inline View): 하나의 테이블 처럼 사용 (테이블 대체 용도) WHERE col = (SELECT ...) # 일반 서브쿼리: 하나의 변수(상수)처럼 사용 (서브쿼리의 결과에 따라 달라지는 조건)중첩 서브쿼리(Nested Subquery)
- WHERE 문에 나타나는 서브쿼리
select name, height from user where height > 177; # 조건값을 상수로 할때 select name, height from user where height > (select height from user where name in ('김철수')); # 조건값을 select 로 특정할 때 (단 결과가 값이 하나여야됨) select name, height from user where height = any(select height from user where addr in ('전남')); # 조건에 값이 여러개 들어올땐 any. # any 는 in 과 동일한 의미 # or 를 의미한다 select * from city where population > all(select population from city where district = 'New York'); # all 은 도출된 모든 조건값에 대해 만족할 때 # and 를 의미한다인라인 뷰(Inline View)
- FROM 문에 나타나는 서브쿼리
- 참고로 서브쿼리가 FROM 절에 사용되는 경우 무조건 AS 별칭을 지정해 주어야 한다.
SELECT EX1.name, EX1.salary FROM ( SELECT * FROM employee AS Ii WHERE Ii.office_worker='사원' ) EX1; # 서브쿼리 별칭스칼라 서브쿼리(Scalar Subquery)
- SELECT 문에 나타나는 서브쿼리
- 딴 테이블에서 어떠한 값을 가져올 때 쓰임
- 하나의 레코드만 리턴이 가능하며, 두개 이상의 레코드는 리턴할 수 없다.
- 일치하는 데이터가 없더라도 NULL 값을 리턴할 수 있다. 이는 원래 그룹함수의 특징중에 하나인데 스칼라 서브쿼리 또한 이 특징을 가지고 있다.
SELECT D.DEPTNO, (SELECT MIN(EMPNO) FROM EMP WHERE DEPTNO = D.DEPTNO) as EMPNO FROM DEPT D ORDER BY D.DEPTNODEPTNO EMPNO 10 1 20 10 30 100 40 1000 50 10000 60 100000 70 80 서브쿼리 실행 조건
- 서브쿼리는 SELECT 문으로만 작성 할 수 있다. (SELECT 문 쿼리할때 밖에 사용할 때가 없다)
- 반드시 괄호()안에 존재한다.
- 괄호가 끝나고 끝에 ;(세미콜론)을 쓰지 않는다
- ORDER BY 를 사용할 수 없다.
서브쿼리 사용 가능한 곳
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, name VARCHAR(64), salary INT, office_worker VARCHAR(64) ) INSERT INTO employee VALUES(1,'허사장',20000000,'사장'); INSERT INTO employee (name,salary,office_worker) VALUES('유부장',10000000,'부장'); INSERT INTO employee (name,salary,office_worker) VALUES('박차장',5000000,'차장'); INSERT INTO employee (name,salary,office_worker) VALUES('정과장',4000000,'과장'); INSERT INTO employee (name,salary,office_worker) VALUES('정대리',3895000,'대리'); INSERT INTO employee (name,salary,office_worker) VALUES('노사원',2500000,'사원'); INSERT INTO employee (name,salary,office_worker) VALUES('하사원',2000000,'사원'); INSERT INTO employee (name,salary,office_worker) VALUES('길인턴',1000000,'인턴');id name salary office_worker 1 허사장 20,000,000 사장 2 유부장 10,000,000 부장 3 박차장 5,000,000 차장 4 정과장 4,000,000 과장 5 정대리 3,895,000 대리 6 노사원 2,500,000 사원 7 하사원 2,000,000 사원 8 길인턴 1,100,000 인턴 중첩 서브쿼리 - 단일 행
# Nested Subquery - 단일행 # 정대리라는 사람의 직급을 구하시오. select office_worker from employee where office_worker = (select office_worker from employee where name = '정대리') # output employee # TABLE office_worker 대리중첩 서브쿼리 - 복수(다중) 행
- IN, ANY, ALL, EXISTS 등의 연산자로 얻은 서브쿼리 결과 여러개의 행을 반환.
# Nested Subquery - 복수(다중) 행 # 정대리보다 급여가 높은 사람들을 구하시오. select * from employee where salary > ( select salary from employee where name = '정대리' ) # output employee # TABLE id name salary office_worker 1 허사장 20,000,000 사장 2 유부장 10,000,000 부장 3 박차장 5,000,000 차장 4 정과장 4,000,000 과장 # 직급이 사원인 사람들을 구하시오. select * from employee where office_worker in ( select office_worker from employee where office_worker = '사원' ) # output employee # TABLE id name salary office_worker 6 노사원 2,500,000 사원 7 하사원 2,000,000 사원인라인 뷰(Inline View)
# 인라인 뷰(Inline View) # 잘못된 구문 - 꼭 파생 테이블엔 별칭을 정해줘야 한다 select * from (select * from employee where office_worker='사원') (X) /* SQL 오류 (1248): Every derived table must have its own alias */ # 직급이 사원인 사람들의 이름과 급여를 구하시오. select EX1.name, EX1.salary from ( select * from employee as Ii where Ii.office_worker='사원' ) EX1; # output EX1 # TABLE name salary 노사원 2,500,000 하사원 2,000,000스칼라 서브쿼리(Scalar Subquery)
# 스칼라 서브쿼리(Scalar Subquery) # 정대리 급여와 테이블 전체 평균 급여를 구하시오. select name, salary, ( select ROUND(AVG(salary),-1) from employee) as '평균급여' from employee where name = '정대리'; # output employee # TABLE name salary 평균급여 정대리 3,895,000 6,061,880INSERT 문 서브쿼리 (INSERT Subquery)
# 테이블2의 정보를 뽑아서 그 데이터를 테이블1에 넣어준다. # values() 들어갈 자리를 서브쿼리로 대체 했다. insert into table1 (select * from table2);DELETE 문 서브쿼리 (DELETE Subquery)
# 인턴의 정보를 구해와서 삭제한다 delete from employee where id = (select id from employee where office_worker = '인턴');UPDATE 문 서브쿼리 (UPDATE Subquery)
# 인턴에 정보를 구해와서 급여를 10만원 인상한다. update employee set salary=(salary+100000) where id = (select id from employee where office_worker = '인턴');'MySQL' 카테고리의 다른 글
Unique Key와 함께보는 DB Transaction (0) 2024.04.22 DB 인덱스(index) 를 알아보자 (0) 2023.06.05 조인(JOIN) 과 서브쿼리(Subquery) 차이는 무엇일까 (0) 2023.06.04