[MySQL || MariaDB] 서브쿼리(Subquery) 총 정리
서브쿼리(Subquery)
개념
하나의 SQL 문 안에 포함되어 있는 또 다른 SQL문을 말한다.
서브쿼리는 메인쿼리가 서브쿼리를 포함하는 종속적인 관계이다.
이제부터 앞에 있는 쿼리 select * from ex를 메인 쿼리
(select * from sub_ex) 괄호()안에 있는 쿼리를 서브 쿼리라 칭합니다.
서브쿼리(자식쿼리) - 메인쿼리 컬럼 사용 가능
메인쿼리(부모쿼리) - 서브쿼리 컬럼 사용 불가
Java의 상속과 똑같은 개념입니다.
종류
중첩 서브쿼리( Nested Subquery ) - WHERE 문에 나타나는 서브쿼리
1.단일 행
2.복수(다중) 행
3.다중 컬럼
인라인 뷰(Inline View) - FROM 문에 나타나는 서브쿼리
스칼라 서브쿼리( Scalar Subquery ) - SELECT 문에 나타나는 서브쿼리
이 세개의 종류는 그냥 외워주세요.
WHERE 중첩 서브쿼리
FROM 인라인 뷰
SELECT 스칼라 서브쿼리
실행 순서
서브쿼리 실행 -> 메인(부모) 쿼리 실행
사용 이유
예를 들어 회사원 테이블에 김동식 대리보다 급여를 많이 받는 사람을 구하시오.
위와 같은 상황이 주어지면 서브쿼리가 없을 경우 우리는 일단
김대리의 급여가 얼만지 모르니까
select salary from employee where name = '김대리'로 김대리의 정보를 구한다음
그 정보를 저장했다가
select name,salary from employee where salary > 김대리 급여 저장한 정보
벌써 피곤합니다.
하지만 서브 쿼리를 쓴다면
select name,salary from employee where salary > (select salary from employee where name = '김대리')
한줄로 *깰끔하게 정리가 됩니다.
이것은 예시일 뿐입니다. 값을 구할 땐 무조건 PK_id로….
*깰끔 : 깔끔의 인터넷 용어
한마디로
여러번의 쿼리를 수행해야만 얻을 수 있는 결과를
하나의 중첩된 SQL문장으로 간편하게 결과를 얻을 수 있게 해줍니다.
조건
서브쿼리는 SELECT문으로만 작성 할 수 있다.
(SELECT문 쿼리밖에 사용 할 수 없는것 이다. SELECT문에만 사용 하는 것이 아니라)
반드시 괄호()안에 존재하여야 한다.
괄호가 끝나고 끝에 ;(세미콜론)을 쓰지 않는다.
ORDER BY를 사용 할 수 없다.
사용 가능 한 곳
SELECT
FROM
WHERE
HAVING
ORDER BY
INSERT문의 VALUES
UPDATE문의 SET
서브쿼리도 별칭(alias) 사용이 가능하다.
문법
문법에 들어가기 앞서, 공통 테이블 예시
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,'인턴');
SELECT * FROM employee
회사원 정보 테이블
서브쿼리는 무조건! 괄호()로 감싼 뒤 사용해야 한다.
(SELECT ~ 서브쿼리 내용)
중첩 서브쿼리 - 단일 행
#Nested Subquery - 단일 행
#정대리라는 사람의 직급을 구하시오.
SELECT office_worker
FROM employee
WHERE office_worker = (SELECT office_worker FROM employee WHERE name = '정대리')
중첩 서브쿼리 - 복수(다중) 행
-IN, ANY, ALL, EXISTS 등의 연산자로 얻은 서브쿼리 결과 여러개의 행을 반환.
#Nested Subquery - 복수(다중) 행
#정대리보다 급여가 높은 사람들을 구하시오.
SELECT *
FROM employee
WHERE salary > (
SELECT salary
FROM employee
WHERE NAME = '정대리')
#직급이 사원인 사람들을 구하시오.
SELECT *
FROM employee
WHERE office_worker IN (
SELECT office_worker
FROM employee
WHERE office_worker = '사원')
인라인 뷰(Inline View)
#인라인 뷰(Inline View)
#잘못된 구문 - 꼭 파생 테이블엔 별칭을 정해줘야 합니다.
SELECT * FROM (SELECT * FROM employee WHERE office_worker='사원') (X)
/* SQL 오류 (1248): Every derived table must have its own alias */
#인라인 뷰(Inline View)
#직급이 사원인 사람들의 이름과 급여를 구하시오.
SELECT EX1.name,EX1.salary
FROM (
SELECT *
FROM employee AS Ii
WHERE Ii.office_worker='사원') EX1;
스칼라 서브쿼리(Scalar Subquery)
#스칼라 서브쿼리(Scalar Subquery)
#정대리 급여와 테이블 전체 평균 급여를 구하시오.
SELECT name,salary,(
SELECT ROUND(AVG(salary),-1)
FROM employee) AS '평균급여'
FROM employee
WHERE name = '정대리';
INSERT 문 서브쿼리(INSERT Subquery)
#테이블2의 정보를 뽑아서 그 데이터를 테이블1에 넣어준다.
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 기준
in 함수와 subquery는 성능이 좋지 않으므로 잘 쓰지 않는다.
IN ()은 INNER JOIN 혹은 EXISTS로 변환(대체) 가능
NOT IN()은 LEFT OUTER JOIN 혹은 NOT EXISTS로 변환가능하다
예제 파일 제공
'MariaDB' 카테고리의 다른 글
[MySQL || MariaDB] 데이터 파일 IMPORT 하기(Feat.LOAD DATA INFILE) (0) | 2019.11.15 |
---|---|
[MySQL || MariaDB] 자주 쓰는 날짜 API와 날짜 실전 예제 총 정리 (1) | 2019.11.12 |
[MySQL || MariaDB] AUTO_INCREMENT 옵션 총 정리 (3) | 2019.11.10 |
[Mysql || MariaDB] JOIN 총 정리 (0) | 2019.11.10 |
[Mysql || MariaDB] Select 문 한번에 여러 개 Count()카운트 조회 (0) | 2019.10.31 |