# [ 살펴보기 ] Sql - 서브쿼리

서브쿼리는 다른 쿼리 구문에 포함되는 쿼리구문을 말한다. 괄호 안에 서브쿼리를 작성하여 서브쿼리를 포함하고 있는 포함 쿼리 보다 먼저 실행되고 그 결과를 포함쿼리에서 사용할 수 있다.

다음 예제를 살펴보자

```javascript
SELECT actor_id, film_id 
FROM film_actor 
WHERE film_id IN (SELECT film_id FROM film WHERE rating = "PG")
```

위의 예제에서 서브쿼리는 `(SELECT film_id FROM film WHERE rating = "PG")` 부분이다. 서브쿼리가 반환한 데이터가 포함 구문이 필요한 조회를 할 때 사용되는 것이다.

위의 예제는 film 이라는 table에서 rating이 PG인 영화의 id를 찾고 그 결과를 기준으로 film\_actor라는 table에서 해당 film\_id 데이터를 가진 actor id를 찾는다.

서브쿼리에는 포함 구문과 독립적으로 처리되는 비상관 서브쿼리와 포함 구문의 결과 값을 참조하는 상관 서브쿼리로 나뉜다. 먼저 비상관 서브쿼리부터 살펴보자

## 비상관 서브쿼리

포함쿼리의 결과를 참조하지 않고 개별적으로 실행되는 서브쿼리를 말한다. 위에서 살펴봤던 서브쿼리는 포함쿼리의 결과를 참조하지 않고 개별적으로 실행되므로 비상관 서브쿼리다. 또 다른 예제를 한번 살펴보자

```javascript
SELECT rental_id, customer_id, rental_date, return_date, 
FROM rental
WHERE customer_id 
IN (SELECT customer_id FROM customer WHERE first_name LIKE "J%")
```

위의 예제에선 `(SELECT customer_id FROM customer WHERE first_name LIKE "J%")` 서브쿼리를 통해 first\_name이 J로 시작하는 customer를 기준으로 필요한 데이터를 포함쿼리에서 조회하고 있다.

서브쿼리에서도 JOIN과 같은 다소 복잡한 쿼리를 수행할 수도 있다. 다음은 서브쿼리를 이용해 영화 제목이 BA로 시작하는 영화에 출연했던 배우의 정보를 조회하는 쿼리의 예제이다

```javascript
SELECT actor_id, first_name 
FROM actor
WHERE actor_id IN
(
	SELECT film_actor.actor_id  FROM film_actor
	INNER JOIN film 
	ON film_actor.film_id  = film.film_id
	WHERE film.title LIKE 'BA%' 
)
ORDER BY actor.actor_id 
```

## 상관 서브쿼리

위에서 살펴본 서브쿼리 예제들은 비상관 서브쿼리로서 포함 구문의 결과를 조회하지 않고 서브쿼리로 부터 독립적인 쿼리였다면 상관 서브쿼리는 포함 구문의 결과를 참조하고 포함 구문의 결과에 의존하여 서브쿼리가 수행된다.

다음 예제를 살펴보자

```javascript
SELECT actor_id, first_name 
FROM actor
WHERE first_name IN
(
	SELECT first_name FROM customer 
	WHERE actor.first_name = customer.first_name 
)
ORDER BY actor.first_name 
```

위의 예제에서는 서브쿼리에서 조건 필터를 위해 포함 쿼리인 actor table에 의존하고 있다. 주의할 점은 상관 쿼리를 사용하면 포함쿼리의 모든 행에 실행되므로 포함쿼리가 반환하는 행의 숫자가 크면 성능문제가 발생할 수 있으니 주의가 필요하다

상관 서브쿼리는 update나 delete와 같이 쿼리문에 유용하게 사용될 수 있다. 실용적인 예는 아니지만 예를 들어 위의 예제처럼 customer table에 같은 first\_name이 존재하는 actor 테이블의 city column을 일괄적으로 변경하고 싶다면 다음과 같이 처리할 수 있을 것 이다

```javascript
UPDATE actor 
SET city = "new town"
WHERE first_name IN
(
	SELECT first_name FROM customer 
	WHERE actor.first_name = customer.first_name 
)
```

## 서브쿼리의 결과를 데이터 소스로 사용

위의 예제에서 살펴보았듯이 서브쿼리의 결과를 데이터 소스로서 사용할 수 있다. 다음의 예제와 같이 JOIN절의 대상으로도 활용 가능하다

```javascript
SELECT customer.customer_id, customer.first_name FROM customer
INNER JOIN 
(
  SELECT first_name FROM actor WHERE first_name LIKE "A%"
) AS actorRecord
ON customer.first_name = actorRecord.first_name
```

위의 예제는 서브쿼리의 결과는 JOIN의 대상으로 활용하는 예이다. 서브쿼리에서 first\_name이 A로 시작하는 actor를 찾고 그 결과를 기반으로 포함쿼리에서 같은 first\_name을 가진 데이터를 조회한다
