> ## 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 INSERT SELECT

> INSERT INTO ... SELECT가 쿼리의 행을 MySQL 테이블로 어떻게 복사하는지, 열이 어떻게 짝지어지는지, 그리고 짝이 맞지 않을 때 ERROR 1136이 무엇을 말하는지 설명합니다.

> [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 →

`VALUES`는 직접 입력한 행을 제공합니다. 그 자리에 쓴 `SELECT`는 서버가 계산한 행을 제공하므로, 쿼리할 수 있는 요약은 저장할 수 있는 요약입니다. 보고서 테이블을 채우는 방법이고, 행을 한 테이블에서 다른 테이블로 옮기는 방법입니다.

이 예제들은 [INSERT](https://villagesql.com/docs/ko/tutorial/insert.md)의 `sakila_practice` 데이터베이스를 사용합니다. 시작하기 전에 거기 있는 설정 블록을 다시 실행한 다음, `mysql -u root -p sakila_practice`로 클라이언트를 여세요.

## INSERT SELECT의 동작 방식

```sql theme={null}
INSERT INTO TARGET_TABLE (COLUMN_LIST)
SELECT SOURCE_COLUMNS FROM SOURCE_TABLE;
```

`TARGET_TABLE`을 쓰기 대상 테이블로, `COLUMN_LIST`를 그 테이블의 열로, `SOURCE_COLUMNS`를 쿼리가 반환하는 것으로, `SOURCE_TABLE`을 읽는 테이블로 바꾸세요.

`VALUES` 키워드는 없습니다. 열은 위치로 짝지어지므로, `SELECT`가 반환하는 첫 번째 것이 첫 번째로 지정한 열에 들어가고, 둘의 이름이 무엇인지는 상관없습니다. 쿼리가 반환하는 모든 행이 대상 테이블의 행이 됩니다.

## 예제

### 요약 저장

`rating_count`는 비어 있고 `sakila.film`이 답을 가지고 있습니다. 테이블을 `database.table`로 지정하면 다른 데이터베이스에서 읽으므로, 문 1개가 2개의 데이터베이스를 넘나들 수 있습니다.

```sql theme={null}
INSERT INTO rating_count (rating, films)
SELECT rating, COUNT(*) FROM sakila.film GROUP BY rating;
```

```text theme={null}
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0
```

`GROUP BY`가 5개의 행을 만들었고 5개의 행이 쓰였습니다.

```sql theme={null}
SELECT * FROM rating_count ORDER BY films DESC;
```

```text theme={null}
+--------+-------+
| rating | films |
+--------+-------+
| PG-13  |   223 |
| NC-17  |   210 |
| R      |   195 |
| PG     |   194 |
| G      |   178 |
+--------+-------+
5 rows in set (0.00 sec)
```

이제 이것은 보통의 행이고, 스냅샷입니다. `film`이 바뀌어도 아무것도 이 행을 갱신하지 않습니다.

### 들어가는 길에 값 만들기

`SELECT`는 무엇이든 계산할 수 있으므로, 들어가는 행이 그 모양 그대로 어딘가에 존재할 필요는 없습니다.

```sql theme={null}
INSERT INTO member (first_name, last_name, email, joined)
SELECT first_name, last_name, CONCAT(LOWER(first_name), '.', LOWER(last_name), '@example.net'), '2026-05-01'
FROM sakila.staff;
```

```text theme={null}
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0
```

```sql theme={null}
SELECT member_id, first_name, last_name, email FROM member WHERE joined = '2026-05-01';
```

```text theme={null}
+-----------+------------+-----------+--------------------------+
| member_id | first_name | last_name | email                    |
+-----------+------------+-----------+--------------------------+
|         4 | Mike       | Hillyer   | mike.hillyer@example.net |
|         5 | Jon        | Stephens  | jon.stephens@example.net |
+-----------+------------+-----------+--------------------------+
2 rows in set (0.00 sec)
```

주소 열은 `CONCAT`으로 만들었고 날짜는 모든 행에 반복되는 상수입니다.

## ERROR 1136은 2개의 목록 길이가 다르다는 뜻입니다

```sql theme={null}
INSERT INTO rating_count (rating, films)
SELECT rating FROM sakila.film GROUP BY rating;
```

```text theme={null}
ERROR 1136 (21S01): Column count doesn't match value count at row 1
```

2개의 열을 지정했고, 1개가 반환되었습니다. 이 오류가 나타날 때는 언제나 2개의 목록 길이가 다르므로, 세어 보세요. 아무것도 이름이나 의미를 검사하지 않으므로, 개수는 맞지만 엉뚱한 열을 반환하는 `SELECT`는 받아들여지고 엉터리 데이터를 씁니다. 먼저 `SELECT`를 따로 실행해서 무엇이 돌아오는지 읽으세요.

## 두 번째 실행은 테이블의 키와 만납니다

쿼리가 반환하는 모든 행이 테이블에 제시되고, 테이블의 규칙은 여전히 적용됩니다.

```sql theme={null}
INSERT INTO rating_count (rating, films)
SELECT rating, COUNT(*) FROM sakila.film WHERE rating = 'G' GROUP BY rating;
```

```text theme={null}
ERROR 1062 (23000): Duplicate entry 'G' for key 'rating_count.PRIMARY'
```

`rating`이 기본 키이고 `G`는 이미 저장되어 있습니다. 한 번 만들고 마는 것이 아니라 새로 고치고 싶은 요약에는 [upsert](https://villagesql.com/docs/ko/tutorial/upsert.md)가 필요한데, 실패하는 대신 저장된 행을 갱신합니다.

## 요약

* `VALUES`가 들어갈 자리에 `SELECT`를 두고, `VALUES` 키워드는 쓰지 마세요.
* 열은 이름이 아니라 언제나 위치로 짝지어집니다.
* `ERROR 1136`은 2개의 목록 길이가 다르다는 뜻으로 읽으세요.
* 같은 문에서 다른 데이터베이스를 읽으려면 테이블을 `database.table`로 지정하세요.
* 두 번째 실행은 다른 삽입과 마찬가지로 대상 테이블의 키에 부딪힙니다.

## 함께 보기

* [INSERT](https://villagesql.com/docs/ko/tutorial/insert.md) — 직접 입력한 값을 받는 형태
* [여러 행 삽입](https://villagesql.com/docs/ko/tutorial/insert-multiple-rows.md) — 쿼리 없이 여러 행
* [Upsert](https://villagesql.com/docs/ko/tutorial/upsert.md) — 두 번째 실행이 충돌할 행 새로 고치기
* [MySQL의 대량 삽입](https://villagesql.com/docs/ko/guides/bulk-inserts.md) — 큰 양을 옮기기, 그리고 그 비용


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