본문 바로가기

IT Story/SQL Story

서브 쿼리

쿼리 안에 포함되는 또 다른 쿼리.

서브 쿼리는 조인하지 않은 상태에서 다른 테이블과 일치하는 행을 찾거나, 조인 결과를 다시 조인할 때 사용할 수 있다.

 

서브 쿼리의 특징

  • 반드시 소괄호로 감싸 사용한다.
  • 주 쿼리를 실행하기 전에 1번만 실행된다.
  • 비교 연산자에 서브 쿼리를 사용하는 경우 서브 쿼리를 오른쪽에 기술해야 한다.
  • 내부에는 정렬 구문인 ORDER BY 문을 사용할 수 없다.

Where 문에서 서브 쿼리 사용하기

where 문에서 사용하는 서브 쿼리를 중첩 서브 쿼리라고 한다. 

중첩 서브 쿼리는 조건문의 일부로 사용한다. 

서브 쿼리를 비교 연산자 =, <, <=, >, >=, <>와 함께 사용할 때는 반드시 서브 쿼리의 반환 결과가 1건 이하여야 한다.

반환 결과가 2건 이상인 경우에는 다중 행 연산자를 사용해야 한다. 

다중 행 연산자 설명
IN 서브 쿼리의 결과에 존재하는 임의의 값과 같은 조건 검색
ANY 서브 쿼리의 결과에 존재하는 어느 하나의 값이라도 만족하는 조건 검색
EXISTS 서브 쿼리의 결과를 만족하는 값이 존재하는지 여부 확인
ALL 서브 쿼리의 결과에 존재하는 모든 값을 만족하는 조건 검색

단일 행 서브 쿼리

서브 쿼리의 결과가 1행만 반환되는 쿼리

SELECT [열 이름]

FROM [테이블]

WHERE [열] = ( SELECT [열] FROM [테이블] )

 

Select from nasdaq_company
where symbol = (select symbol from nasdaq_company where symbol IN ('MSFT'))

(→ select symbol from nasdaq_company where symbol IN ('MSFT') : 결과 symbol= 'MSFT') 

→ Select * from nasdaq_company where symbol = 'MSFT' 와 같다)

 

만일 Where 문에 사용한 서브 쿼리가 다중 행을 반환하면 비교 연산자 규칙에 어긋나 에러가 발생한다. 

Select from nasdaq_company
where symbol = (select symbol from nasdaq_company where symbol IN ('MSFT', 'AMD', 'AMZN'))

 

다중 행 서브 쿼리

서브 쿼리에서 반환되는 결과가 2행 이상인 경우

 

IN, NOT IN 문

SELECT [열 이름]

FROM [테이블]

WHERE [열] IN ( SELECT [열] FROM [테이블] )

 

Select from nasdaq_company
where symbol IN ('MSFT', 'AMD', 'AMZN')
=
Select from nasdaq_company
where symbol IN (select symbol from nasdaq_company where symbol IN ('MSFT', 'AMD', 'AMZN'))

 

서브 쿼리에 검색된 3개의 행이 메인 쿼리의 조건으로 사용된 것을 알 수 있다. 

 

다음은 3개의 테이블을 사용해 조인하는 쿼리를 IN문 서브 쿼리를 사용해 변경한 것이다.

  • 3개 테이블 조인

select
a.industry,
c.symbol,
c.company_name,
c.ipo_year,
c.sector
from industry_group as a
inner join industry_group_symbol as b on a.num = b.num
inner join nasdaq_company as c on b.symbol = c.symbol
where a.industry = N'자동차'
order by symbol

 

  • IN 문 서브 쿼리

select
*
from nasdaq_company
where symbol IN (
Select symbol from industry_group as a
Inner join  industry_group_symbol as b on a.num = b.num
where a.industry = N'자동차'
)

→ 자동차 행을 검색

(서브 쿼리) 해석: industry_group 과 industry_group_symbol의 a.num = b.num 조건을 만족하는 내부 조인으로 생성된 테이블에서 symbol 열만 추출하겠다. 

전체적으로는 nasdaq_company 테이블의 모든 열 중에 Where문 조건(symbol)을 만족하는 열을 추출하겠다.

 

  • NOT IN 문 서브 쿼리

select
*
from nasdaq_company
where symbol NOT IN (
Select symbol from industry_group as a
Inner join  industry_group_symbol as b on a.num = b.num
where a.industry = N'자동차'
)

→ 자동차가 아닌 행을 검색

 

ANY 문

select
*
from nasdaq_company
where symbol = ANY (
Select symbol from nasdaq_company
where symbol IN ('MSFT', 'AMD', 'AMZN')
)

해석: symol이 'MSFT', 'AMD', 'AMZN'인 조건을 하나라도 만족하는 모든 행을 주 쿼리에에서 검색해 반환한다.

 

select
*
from nasdaq_company
where symbol < ANY (
Select symbol from nasdaq_company
where symbol IN ('MSFT', 'LTCH', 'ZY')
)

해석:  < ANY 서브 쿼리 결과와 비교해 최솟값을 반환한다.

 

select
*
from nasdaq_company
where symbol > ANY (
Select symbol from nasdaq_company
where symbol IN ('MSFT', 'LTCH', 'ZY')
)

해석:  > ANY 서브 쿼리 결과와 비교해 최댓값을 반환한다.

 

EXISTS, NOT EXISTS

조건의 결괏값이 있는지 없는지를 확인해 1행이라도 있으면 TRUE, 없으면 FALSE를 반환

where 문에 exists 문을 사용해 서브 쿼리의 결괏값이 1행이라도 있으면 True가 되어 메인 쿼리를 실행하고, 메인 쿼리에 작성된 전체 데이터를 검색한다. 

select * from nasdaq_company
where exists(
select symbol from nasdaq_company
where symbol in  ('MSFT', 'AMD', 'AMZN')
)

서브 쿼리의 결괏값이 0건 반환되면 메인 쿼리가 실행되지 않고 아무것도 나타나지 않는다. 

select * from nasdaq_company
where exists(
select symbol from nasdaq_company
where symbol in  ('123', '456', '789')
)

NOT EXISTS는 EXISTS와 반대로 작동한다. 

select * from nasdaq_company
where not exists(
select symbol from nasdaq_company
where symbol in  ('123', '456', '789')
)

ALL 문

서브 쿼리 결괏값에 있는 모든 값을 만족하는 조건을 주 쿼리에서 검색해 결과를 반환한다. 

select from nasdaq_company
where symbol = all(
select symbol from nasdaq_company
where symbol in  ('MSFT', 'AMD', 'AMZN')
)

 

FROM 문에서 서브 쿼리 사용하기

보통 인라인뷰라고 한다. 

SELECT [열 이름]

FROM [테이블] AS a

INNER JOIN (SELECT [열] FROM  [테이블] WHERE [열] =[값] ) AS b ON [a.열] =[b.열]

WHERE [열] = [값] 

 

인라인뷰에 inner join 문을 활용한 서브 쿼리
-테이블 내부조인
SELECT 
a.symbol, a.company_name, a.ipo_year, a.sector, a.industry,
b.date, b.[open], b.[high], b.[low], b.[close], b.adj_close, b.volume
FROM nasdaq_company As a
     INNER JOIN stock as b ON a.symbol = b.symbol
where a.symbol = 'MSFT'
AND b.date >= '2021-10-01'
AND b.date < '2021-11-01'
order by date

-서브 쿼리
SELECT 
a.symbol, a.company_name, a.ipo_year, a.sector, a.industry,
b.date, b.[open], b.[high], b.[low], b.[close], b.adj_close, b.volume
FROM nasdaq_company As a
INNER JOIN  ( Select symbol, date, [open], [high],[low], [close], adj_close, volume
                       from stock 
                       where symbol = 'MSFT'
                       AND date >= '2021-10-01'
                       AND date < '2021-11-01'
                     ) as b ON a.symbol = b.symbol

 

SELECT 문에서 서브 쿼리 사용하기

select 문에 사용된 서브 쿼리를 스칼라 서브 쿼리라고 하며, 1개 이상 사용할 수 있다. 

SELECT [열 이름]

       (SELECT <집계 함수> [열 이름]  FROM  [테이블 2]

        WHERE [테이블2.열] =[테이블1. 열] ) AS Alias

FROM [테이블 1]

WHERE [열] = [값] 

 

-테이블 내부조인
SELECT 
a.symbol, a.company_name, a.ipo_year, a.sector, a.industry,
b.date, b.[open], b.[high], b.[low], b.[close], b.adj_close, b.volume
FROM nasdaq_company As a
     IINNER JOIN stock as b ON a.symbol = b.symbol
where a.symbol = 'MSFT'
AND b.date >= '2021-10-01'
AND b.date < '2021-11-01'
order by date

-서브 쿼리
SELECT 
a.symbol, 

(Select company_name From nasdaq_company  As b where b.symbol = a.symbol) As company_name,

(Select ipo_year  From nasdaq_company  As b where b.symbol = a.symbol) As ipo_year,

(Select sector From nasdaq_company  As b where b.symbol = a.symbol) As sector ,

(Select industry From nasdaq_company  As b where b.symbol = a.symbol) As industry,

a.date, a.[open], a.[high], a.[low], a.[close], a.adj_close, a.volume
FROM stock As a
where a.symbol = 'MSFT'
AND a.date >= '2021-10-01'
AND a.date < '2021-11-01'
order by date

 

퀴즈3. nasdaq_company  테이블에서 sector 열의 값이 Energy인 데이터 중에 industry_group_symbol 테이블에 포함되지 않은 symbol, company_name을 검색하세요

.

  • 인라인뷰를 사용한 코드

SELECT 
a.symbol, a.company_name, s_b.symbol
FROM nasdaq_company As a
LEFT OUTER JOIN (
    SELECT symbol
FROM industry_group as a
      INNER JOIN industry_group_symbol AS b ON a.num = b.num
WHERE a.industry = 'Oil') AS s_b ON a.symbol = s_b.symbol
WHERE a.sector =' Energy'
AND s_b.symbol IS NULL

 

  • 중첩 서브 쿼리를 사용한 코드

SELECT symbol, company_name
FROM nasdaq_company
WHERE sector = 'Energy'
AND symbol NOT IN (
     SELECT symbol 
    FROM industry_group AS a
     INNER JOIN industry_group_symbol AS b ON a.num = b.num
     WHERE a.industry = 'Oil'
    )

 

'IT Story > SQL Story' 카테고리의 다른 글

SQL 함수: 문자열 함수  (0) 2022.12.02
공통 테이블 식(Common Table Expression, CTE)  (0) 2022.12.01
조인(Join): 외부 조인  (0) 2022.11.29
조인(Join): 내부 조인  (0) 2022.11.28
SQL 시작하기: CREATE 문  (0) 2022.11.24