> ## 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 파생 테이블

> FROM 절의 서브쿼리가 쿼리할 수 있는 테이블이 되는 방법, 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 →

`WHERE`의 서브쿼리는 값을 제공합니다. `FROM`의 서브쿼리는 테이블 전체를 제공하고, 바깥 쿼리는 그것을 실제 테이블인 것처럼 읽습니다. 그것이 파생 테이블이고, 쿼리의 결과를 쿼리하는 방법입니다.

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

## 파생 테이블의 동작 방식

```sql theme={null}
SELECT COLUMN_LIST
FROM (SELECT COLUMN_LIST FROM TABLE_NAME) AS ALIAS_NAME;
```

`COLUMN_LIST`를 원하는 열로, `TABLE_NAME`을 안쪽 쿼리가 읽는 테이블로, `ALIAS_NAME`을 결과의 이름으로 바꾸세요. 별칭을 포함한 안쪽 쿼리의 열 이름이 파생 테이블의 열이 됩니다.

서버는 안쪽 결과를 먼저 만든 다음, 그 위에서 바깥 쿼리를 실행합니다.

## 이것이 가능하게 하는 것

`GROUP BY`는 상세 행을 그룹마다 1개의 행으로 바꾸므로, 그룹화된 쿼리는 행 자체를 보여 줄 수 없습니다. 파생 테이블은 둘 다 유지합니다: 안쪽 쿼리에서 그룹화한 다음, 그 결과를 상세 행에 다시 조인합니다.

이 쿼리는 자기 등급의 평균보다 긴 영화를 나열하고, 각 영화 옆에 그 평균을 보여 줍니다.

```sql theme={null}
SELECT f.title, f.length, r.mean_for_rating
FROM film AS f
INNER JOIN (
  SELECT rating, AVG(length) AS mean_for_rating
  FROM film
  GROUP BY rating
) AS r ON r.rating = f.rating
WHERE f.length > r.mean_for_rating
ORDER BY f.rating, f.title
LIMIT 5;
```

```text theme={null}
+------------------+--------+-----------------+
| title            | length | mean_for_rating |
+------------------+--------+-----------------+
| AFFAIR PREJUDICE |    117 |        111.0506 |
| AFRICAN EGG      |    130 |        111.0506 |
| ALAMO VIDEOTAPE  |    126 |        111.0506 |
| ATLANTIS CAUSE   |    170 |        111.0506 |
| BAKED CLEOPATRA  |    182 |        111.0506 |
+------------------+--------+-----------------+
5 rows in set (0.00 sec)
```

`WHERE`나 [HAVING](https://villagesql.com/docs/ko/tutorial/having.md)만으로는 이것을 작성할 수 없습니다. `HAVING`은 그룹을 필터링하므로 제목을 버렸을 것이고, `WHERE`는 어떤 평균도 존재하기 전에 실행됩니다. 5개의 평균은 안쪽 쿼리에서 한 번 계산되고, 조인이 모든 영화에 알맞은 평균을 붙입니다.

[상관 서브쿼리](https://villagesql.com/docs/ko/tutorial/correlated-subqueries.md) 레슨은 같은 질문에 한 번에 한 행씩 답합니다. 이 형태는 대신 평균을 한 번만 계산합니다.

## 별칭은 선택 사항이 아닙니다

```sql theme={null}
SELECT rating, films
FROM (SELECT rating, COUNT(*) AS films FROM film GROUP BY rating)
WHERE films > 200;
```

```text theme={null}
ERROR 1248 (42000): Every derived table must have its own alias
```

`ERROR 1248`은 항상 이것을 뜻하고, 해결 방법도 항상 같습니다: 닫는 괄호 뒤에 `AS SOME_NAME`을 넣으세요. 이름은 무엇이든 될 수 있고, 행을 설명하는 이름으로 만들 만한데, 독자가 그것을 만든 쿼리를 읽기 전에 그 이름을 먼저 만나기 때문입니다.

## 파생 테이블 또는 CTE

[공통 테이블 표현식](https://villagesql.com/docs/ko/tutorial/cte.md)은 서브쿼리를 맨 위로 끌어올려 이름을 붙인 채로 같은 일을 합니다. 2가지 형태는 같은 행을 만들어내며, 다음 레슨이 그 차이를 다룹니다. [MySQL CTE가 파생 테이블을 이기는 때](https://villagesql.com/docs/ko/guides/ctes-in-mysql.md)가 옵티마이저가 어느 쪽을 다르게 다루는지 측정합니다.

## 요약

* 쿼리의 결과를 쿼리하려면 파생 테이블을 사용하세요.
* 별칭이 없으면 `ERROR 1248`이 나오므로, 별칭을 주세요.
* 안쪽 쿼리의 열 별칭이 파생 테이블의 열이 된다고 예상하세요.
* 계산된 열로 필터링하거나 조인해야 할 때 파생 테이블을 쓰세요.
* 쿼리에 여러 단계가 있거나 같은 서브쿼리를 반복하게 되면 CTE를 쓰세요.

## 함께 보기

* [공통 테이블 표현식](https://villagesql.com/docs/ko/tutorial/cte.md) — 같은 아이디어를 맨 위에 쓴 것
* [HAVING](https://villagesql.com/docs/ko/tutorial/having.md) — 파생 테이블 없이 그룹 필터링하기
* [서브쿼리](https://villagesql.com/docs/ko/tutorial/subqueries.md) — 대신 값으로 쓰이는 서브쿼리
* [MySQL CTE가 파생 테이블을 이기는 때](https://villagesql.com/docs/ko/guides/ctes-in-mysql.md) — 옵티마이저가 둘을 다르게 다루는 때


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