> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MySQL 상관 서브쿼리

> MySQL의 상관 서브쿼리가 바깥 행의 열을 읽는 방법, 그 때문에 행마다 한 번씩 실행되는 이유, 그리고 그 비용을 치를 만한 때입니다.

> [card] [VillageSQL is a drop-in replacement for MySQL with extensions.](https://villagesql.com/docs/en/8.4/stable/install-server.md)
>
> All examples on this page work on VillageSQL. Install Now →

보통의 서브쿼리는 한 번 실행되고 답을 돌려줍니다. 상관 서브쿼리는 바깥 쿼리의 열을 이름으로 부르므로, 바깥 행마다 다른 답을 가지며 서버는 각 행에 대해 그것을 다시 실행해야 합니다.

시작하기 전에 `mysql -u root -p sakila`로 클라이언트를 여세요.

## 상관 서브쿼리의 동작 방식

```sql theme={null}
SELECT COLUMN_LIST
FROM TABLE_NAME AS OUTER_ALIAS
WHERE COLUMN_NAME > (
  SELECT AGGREGATE_FUNCTION(COLUMN_NAME)
  FROM TABLE_NAME AS INNER_ALIAS
  WHERE INNER_ALIAS.COLUMN_NAME = OUTER_ALIAS.COLUMN_NAME
);
```

`COLUMN_LIST`를 원하는 열로, `TABLE_NAME`을 테이블로, `COLUMN_NAME`을 비교되는 열로, `AGGREGATE_FUNCTION`을 안쪽 쿼리가 실행하는 함수로, `OUTER_ALIAS`와 `INNER_ALIAS`를 관련된 테이블의 2개 이름으로 바꾸세요.
이 2개의 별칭이 동작을 가능하게 하는 것입니다: 안쪽 쿼리가 바깥 쿼리를 이름으로 언급하는데, 그것이 상관입니다.

바깥 행마다 한 번씩, 그 행의 값을 채워 넣고 묻는 질문으로 읽으세요.

## 이것이 답하는 질문

"어떤 영화가 평균보다 긴가"에는 1개의 평균이 필요합니다. "어떤 영화가 **자기 등급의** 평균보다 긴가"에는 행마다 다른 평균이 필요하고, 상관 서브쿼리가 주는 것이 바로 그것입니다.

```sql theme={null}
SELECT f.title, f.rating, f.length
FROM film AS f
WHERE f.length > (SELECT AVG(f2.length) FROM film AS f2 WHERE f2.rating = f.rating)
ORDER BY f.rating, f.title
LIMIT 5;
```

```text theme={null}
+------------------+--------+--------+
| title            | rating | length |
+------------------+--------+--------+
| AFFAIR PREJUDICE | G      |    117 |
| AFRICAN EGG      | G      |    130 |
| ALAMO VIDEOTAPE  | G      |    126 |
...
+------------------+--------+--------+
5 rows in set (0.12 sec)
```

`f2.rating = f.rating`이 중요한 줄입니다. 이것이 안쪽 쿼리를 검사 중인 행에 묶어 주므로, `G` 영화는 `G` 평균과, `R` 영화는 `R` 평균과 비교됩니다.

그 줄을 빼면 서브쿼리는 카탈로그 전체의 평균을 내고, 매번 같은 값이 되며, 쿼리는 다른 질문에 답하게 됩니다.

## 행마다 한 번씩 실행됩니다

위의 실행 시간을 [서브쿼리](https://villagesql.com/docs/ko/tutorial/subqueries.md) 레슨의 쿼리들과 비교해 보세요. 그 쿼리들은 측정할 수 없을 만큼 빨리 돌아옵니다. 이 쿼리는 1,000개 행에 10분의 1초가 걸리는데(여러분의 정확한 수치는 다를 것입니다), 서버가 안쪽 쿼리를 한 번이 아니라 바깥 행마다 평가하기 때문입니다.

그것이 트레이드오프의 전부입니다. 상관 서브쿼리는 "각 행을 자기 그룹과 비교하라"를 쓰는 가장 명확한 방법이고, 비용은 테이블과 함께 커집니다.

MySQL은 일부 상관 서브쿼리를 스스로 조인으로 다시 쓰고, 같은 질문에 1번의 패스로 답하는 다른 형태도 있습니다. [MySQL의 서브쿼리 대 JOIN](https://villagesql.com/docs/ko/guides/subqueries-vs-joins.md)이 둘 다를 다루고, 어느 쪽을 얻었는지 알려 주는 플랜을 읽는 방법도 다룹니다.

## 요약

* 각 행을 자기 그룹에서 계산한 무언가와 비교하려면 상관 서브쿼리를 사용하세요.
* 안쪽 쿼리가 바깥 쿼리를 이름으로 불러야 하므로, 두 테이블 모두에 별칭을 주세요.
* 바깥 행마다 한 번씩 실행된다고 예상하세요.
* 테이블이 크면 파생 테이블과 조인으로 다시 쓰세요.

## 함께 보기

* [서브쿼리](https://villagesql.com/docs/ko/tutorial/subqueries.md) — 한 번만 실행되는, 상관되지 않은 종류
* [EXISTS](https://villagesql.com/docs/ko/tutorial/exists.md) — 값이 아니라 검사로 쓰이는 상관 서브쿼리
* [파생 테이블](https://villagesql.com/docs/ko/tutorial/derived-tables.md) — 더 저렴한 다시 쓰기
* [MySQL의 서브쿼리 대 JOIN](https://villagesql.com/docs/ko/guides/subqueries-vs-joins.md) — 결정하기 위해 플랜 읽기


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.