[목차]
01. 서브쿼리
대표적으로 SELECT, FROM, WHERE 절에서 사용 가능하다.
서브 쿼리(부속 질의) 밖에 있는 쿼리 → 메인 쿼리 또는 주 질의
일반적으로 대량의 데이터를 다루는 경우, 데이터를 모두 합쳐서 연산하는 JOIN보다 필요한 데이터만 찾아서 조회하는 서브 쿼리가 성능이 좋다.
➡️ 서브 쿼리가 단일 행 반환 또는 다중 행을 반환에 따라서 분류 할 수 있다.
- 단일 행 부속 질의
- 서브 쿼리에서 하나의 행을 반환해서 메인 쿼리에 전달한다.
- 스칼라 서브 쿼리, 비교 연산자에서 주로 나타난다.
- 다중 행 서브 쿼리
- 서브 쿼리 결과가 여러 개의 행을 반환하는 경우
- IN연산자를 사용하여 여러 행을 처리할 수 있다.
SELECT절에 사용하는 스칼라 서브쿼리
👉🏻SELECT절에 사용할 수 있다.단일 행과 단일 열의 결괏값을 반환한다.
결괏값이 다중 행 또는 다중 열이면 에러 발생
결과가 없다면 NULL을 출력한다.
➡️ 다중 행 또는 다중 열이라면, DBMS가 어떤 값을 출력해야 하는지 알 수 없다. (하나의 값만 출력해야 하는데, 조회 값이 여러 개.)
➡️ 예제
구매자(고객) 별 총 구매 금액과 고객의 이름을 출력하시오.
SELECT -- 스칼라 서브 쿼리 (SELECT m.m_name FROM tb_member AS m WHERE -- 밑에서 사용한 order 테이블의 alias를 쓸 수 있다. m.m_id = o.o_id) AS '고객이름', SUM(o.o_amount * g.g_price) AS '총 구매 금액' FROM -- 총 구매 금액을 알기 위해 상품테이블과 주문테이블을 조인 tb_goods AS g INNER JOIN tb_order AS o ON g.g_code = o.o_g_code -- 구매자(고객) 별로 그룹을 묶는다. GROUP BY o.o_id;
FROM절에 사용하는 인라인 뷰
👉🏻FROM절에 사용하는 서브 쿼리를 말한다.인라인 뷰 라는 이름은 결과를 뷰 형태로 반환하기 때문이다.
- 뷰 : 임시로 만들어진 가상 테이블을 말한다.
FROM절에서 사용한 서브 쿼리의 결과를 하나의 테이블로 사용한다고 생각하면 된다.
인라인 뷰를 사용하면 일반적인 테이블처럼 사용 가능하다.
반환되는 값은 다중 열, 다중 행 전부 가능하다.
➡️ 기본 구문
SELECT
컬럼명
FROM
(SELECT * FROM 테이블명)
JOIN, WHERE 등 사용 가능
➡️ 예제
회원 레벨이 2인 회원들 중, 판매하는 상품 가격이 60만원 이상인 판매자의 ID/이름, 상품 이름, 각 상품의 가격을 조회한 후, 내림차순 정렬
SELECT -- 컬럼 조회 g.g_seller_id AS '판매자ID', m.m_name AS '판매자이름', g.g_name AS '상품이름', g.g_price AS '상품가격' FROM -- 인라인 뷰와 상품 테이블을 조인 (SELECT * FROM tb_member WHERE m_level = 2) AS m INNER JOIN tb_goods AS g m.m_id = g.g_seller_id WHERE -- 조건 g.g_price >= 600000 -- 가격을 내림차순 정렬 ORDER BY g.g_price DESC;
WHERE절에 사용하는 중첩 질의
👉🏻WHERE절에 사용할 수 있다.IN연산자, 비교 연산자를 사용할 수 있다.
➡️ 다중 행 연산자 (IN, ANY 많이 사용)
👉🏻IN- 리턴되는 값 중에서 조건에 해당하는 값이 있으면 참.
- WHERE 컬럼 = 값;
➡️ 이퀄 기호를 사용하면 반환되는 값이 단일 행을 반환하는 경우에만 사용 가능하다.
➡️ IN연산자를 사용하면 반환 값이 여러 개 있을 경우, 다중 행을 반환할 수 있다.
ANY, SOME(=OR)
- 서브 쿼리에 의해 리턴되는 각각의 값과 조건을 비교하여 하나 이상을 만족하면 참이다.
ALL(AND)
- 서브 쿼리에 의해 리턴되는 각각의 값과 조건을 비교하여 모든 값을 만족하면 참이다.
EXISTS, NOT EXISTS
- 데이터의 존재 유무를 확인한다.
- 메인 쿼리의 비교 조건이 서브 쿼리의 결과 중에서 만족하는 값이 하나라도 존재하면 참이다.
➡️ 예제
- goods table에서 각 제품의 평균 가격을 구하시오.
- 평균 가격보다 비싼 가격의 제품 이름과 가격을 조회하시오.
-- 1번 문제 SELECT -- 상품 가격의 평균에 반올림한 값의 컬럼을 조회 ROUND(AVG(g.g_price), 0) FROM tb_goods AS g; -- 2번문제 SELECT -- 제품 이름, 가격을 조회 g.g_name, g.g_price FROM tb_goods AS g WHERE -- 중첩 질의 g.g_price > (SELECT ROUND(AVG(g.g_price), 0) FROM tb_goods AS g;
-- ANY 연산자 (=SOME, OR) SELECT * FROM tb_member AS m WHERE -- level 테이블에서 레벨 번호가 1보다 큰 레벨 번호를 조회하고, -- member테이블의 레벨에서 그 레벨 번호보다 큰 레벨 m.m_level > ANY(SELECT l.level_num FROM tb_member_level AS l WHERE l.level_num > 1); -- ALL 연산자 (=AND) SELECT * FROM tb_member AS m WHERE m.m_level > ALL(SELECT l.level_num FROM tb_member_level AS l WHERE l.level_num > 1); -- EXISTS SELECT * FROM tb_member AS m WHERE EXISTS (SELECT * FROM tb_order AS o WHERE m.m_id = o.o_id);
➡️ 주의사항
- 메인 쿼리의 WHERE절에서 비교하는 컬럼의 수와 서브 쿼리에서 조회하는 컬럼의 수 불일치로 발생하는 에러.
-- 다중 행을 반환할 때, IN연산자 사용 SELECT * FROM city AS c WHERE -- 비교하는 컬럼의 수가 같아야 한다. (2개) (c.CountryCode, c.Name) IN (SELECT c1.CountryCode, c1.Name FROM city AS c1 WHERE c1.CountryCode = 'KOR' OR c1.CountryCode = 'JPN');
쿼리 실행 순서
👉🏻서브 쿼리가 먼저 실행되고, 메인 쿼리가 실행된다.서브 쿼리의 값이 먼저 반환되고, 메인 쿼리에서 비교한다.
중첩 질의는 메인 쿼리가 실행되고, 서브쿼리가 실행된다.
주의사항
👉🏻서브 쿼리는 반드시 () 괄호 안에 작성해야 한다.
02. UNION
여러 SQL문을 합쳐서 하나의 SQL문으로 만드는 방법
예전 테이블의 데이터를 새로 만든 테이블과 함께 추출해야 하는 업무
종류
➡️ UNION(기본값)
👉🏻중복 결과를 없애고 데이터를 출력한다.중복된 행은 한 번만 출력한다.
➡️ UNION ALL
👉🏻중복 데이터까지 포함해서 보여준다.중복된 행도 그대로 출력한다.
특징
➡️ 실행 속도
- UNION ALL 이 더 빠르다. → 중복 상관없이 전부 출력
➡️ 규칙
👉🏻컬럼의 개수가 동일해야 한다.컬럼의 이름을 동일하게 한다. (다를 경우 Alias 사용)
컬럼의 데이터 타입이 동일해야 한다.
➡️ 중요
- UNION 사용 규칙이 DBMS마다 허용하는 범위 차이가 있다.
- 하지만 규칙을 지켜서 작성하는 것이 좋다.
tag : #데이터베이스 #DB #서브쿼리 #스칼라 #인라인뷰 #중첩질의 #UNION
Uploaded by N2T