> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-fix-nav-issues.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> INSERT INTO 语句文档

# INSERT INTO 语句

向表中插入数据。

**语法**

```sql theme={null}
INSERT INTO [TABLE] [db.]table [(c1, c2, c3)] [SETTINGS ...] VALUES (v11, v12, v13), (v21, v22, v23), ...
```

你可以使用 `(c1, c2, c3)` 指定要插入的列列表。你也可以使用带有列[匹配器](/zh/reference/statements/select#asterisk) (如 `*`) 和/或[修饰符](/zh/reference/statements/select#select-modifiers) (如 [APPLY](/zh/reference/statements/select/apply_modifier)、[EXCEPT](/zh/reference/statements/select/except_modifier)、[REPLACE](/zh/reference/statements/select/replace_modifier)) 的表达式。

例如，假设有如下表：

```sql theme={null}
SHOW CREATE insert_select_testtable;
```

```text theme={null}
CREATE TABLE insert_select_testtable
(
    `a` Int8,
    `b` String,
    `c` Int8
)
ENGINE = MergeTree()
ORDER BY a
```

```sql theme={null}
INSERT INTO insert_select_testtable (*) VALUES (1, 'a', 1) ;
```

如果你想将数据插入除列 `b` 之外的所有列，可以使用 `EXCEPT` 关键字。结合上面的语法，你需要确保插入的值数量 (`VALUES (v11, v13)`) 与指定的列数 (`(c1, c3)`) 一致：

```sql theme={null}
INSERT INTO insert_select_testtable (* EXCEPT(b)) Values (2, 2);
```

```sql theme={null}
SELECT * FROM insert_select_testtable;
```

```text theme={null}
┌─a─┬─b─┬─c─┐
│ 2 │   │ 2 │
└───┴───┴───┘
┌─a─┬─b─┬─c─┐
│ 1 │ a │ 1 │
└───┴───┴───┘
```

在此示例中，我们可以看到，第二个插入的行中，`a` 和 `c` 列使用传入的值填充，`b` 列则使用默认值填充。也可以使用 `DEFAULT` 关键字来插入默认值：

```sql theme={null}
INSERT INTO insert_select_testtable VALUES (1, DEFAULT, 1) ;
```

如果列列表未包含所有现有列，其余列将使用以下内容填充：

* 根据表定义中指定的 `DEFAULT` 表达式计算得出的值。
* 如果未定义 `DEFAULT` 表达式，则填充为零和空字符串。

数据可以通过 ClickHouse 支持的任意一种 [格式](/zh/reference/formats) 传递给 INSERT。必须在查询中显式指定格式：

```sql theme={null}
INSERT INTO [db.]table [(c1, c2, c3)] FORMAT format_name data_set
```

例如，以下查询格式与基础形式的 `INSERT ... VALUES` 完全相同：

```sql theme={null}
INSERT INTO [db.]table [(c1, c2, c3)] FORMAT Values (v11, v12, v13), (v21, v22, v23), ...
```

ClickHouse 会移除数据前的所有空格，以及一个换行符 (如果存在) 。构造查询时，建议将数据放在查询运算符后的新一行中；如果数据以空格开头，这一点尤其重要。

示例：

```sql theme={null}
INSERT INTO t FORMAT TabSeparated
11  Hello, world!
22  Qwerty
```

你可以使用[命令行客户端](/zh/concepts/features/tools-and-utilities/clickhouse-local)或[HTTP 接口](/zh/concepts/features/interfaces/http)，将数据与查询分开插入。

<Note>
  如果你想为 `INSERT` 查询指定 `SETTINGS`，则必须在 `FORMAT` 子句*之前*指定，因为 `FORMAT format_name` 之后的所有内容都会被视为数据。例如：

  ```sql theme={null}
  INSERT INTO table SETTINGS ... FORMAT format_name data_set
  ```
</Note>

<div id="constraints">
  ## 约束
</div>

如果表定义了[约束](/zh/reference/statements/create/table#constraints)，系统会检查插入数据中每一行是否满足相应的表达式。如果其中任何一项约束不满足，服务器将引发异常，其中包含约束名称和表达式，并停止该查询。

<div id="data-type-validation">
  ## 数据类型验证
</div>

ClickHouse 仅在创建表 (`CREATE TABLE`) 和修改 schema (`ALTER TABLE`) 时验证允许使用的数据类型 (由 `enable_time_time64_type`、`allow_suspicious_low_cardinality_types`、`allow_suspicious_fixed_string_types` 等设置控制) ，不会在 `INSERT` 时进行验证。

这意味着，如果某个包含不允许数据类型的表已经存在，那么即使 server 上禁用了相应设置，仍然可以向其中插入数据。这是有意为之——表一旦创建完成，insert 操作就不应被控制类型创建的设置所阻止。

例如：

```sql theme={null}
SET enable_time_time64_type = 1;

CREATE TABLE events
(
    `id` UInt64,
    `event_time` Time
)
ENGINE = MergeTree()
ORDER BY id;

SET enable_time_time64_type = 0;

-- 即使该设置现已禁用，此操作仍然有效。
-- 表已存在，因此插入操作不会被阻止。
INSERT INTO events VALUES (1, '14:30:25');

-- 但使用 Time 类型创建新表将会失败。
CREATE TABLE events_new
(
    `id` UInt64,
    `event_time` Time
)
ENGINE = MergeTree()
ORDER BY id; -- ERR: TYPE_TIME_TIME64_IS_NOT_ENABLED
```

<Note>
  因此，较新版本的客户端 (其中某项设置默认启用) 可以向较旧版本的服务器 (其中该设置已禁用) 插入包含不允许的数据类型的数据，前提是目标表已具有相应的列类型。校验是在 DDL 层面强制执行的，而不是在 DML 层面。
</Note>

<div id="inserting-the-results-of-select">
  ## 插入 SELECT 结果
</div>

**语法**

```sql theme={null}
INSERT INTO [TABLE] [db.]table [(c1, c2, c3)] SELECT ...
```

列会根据它们在 `SELECT` 子句中的位置进行映射。不过，它们在 `SELECT` 表达式中的名称与 `INSERT` 目标表中的名称可以不同。如有必要，会执行类型转换。

除 Values 格式外，其他任何数据格式都不允许将值设置为 `now()`、`1 + 2` 等表达式。Values 格式允许在有限范围内使用表达式，但不建议这样做，因为在这种情况下会使用低效的代码来执行这些表达式。

不支持其他修改数据分区片段的查询：`UPDATE`、`DELETE`、`REPLACE`、`MERGE`、`UPSERT`、`INSERT UPDATE`。
不过，你可以使用 `ALTER TABLE ... DROP PARTITION` 删除旧数据。

如果 `SELECT` 子句包含表函数 [input()](/zh/reference/functions/table-functions/input)，则必须在查询末尾指定 `FORMAT` 子句。

若要向非 Nullable 数据类型的列中插入默认值而不是 `NULL`，请启用 [insert\_null\_as\_default](/zh/reference/settings/session-settings#insert_null_as_default) 设置。

`INSERT` 也支持 CTE (公共表表达式) 。例如，以下两条语句是等价的：

```sql theme={null}
INSERT INTO x WITH y AS (SELECT * FROM numbers(10)) SELECT * FROM y;
WITH y AS (SELECT * FROM numbers(10)) INSERT INTO x SELECT * FROM y;
```

<div id="inserting-data-from-a-file">
  ## 从文件中插入数据
</div>

**语法**

```sql theme={null}
INSERT INTO [TABLE] [db.]table [(c1, c2, c3)] FROM INFILE file_name [COMPRESSION type] [SETTINGS ...] [FORMAT format_name]
```

使用上述语法可从存储在**客户端**侧的一个或多个文件中插入数据。`file_name` 和 `type` 是字符串字面量。输入文件的[格式](/zh/reference/formats)必须在 `FORMAT` 子句中设置。

支持压缩文件。压缩类型会根据文件名扩展名自动识别，也可以在 `COMPRESSION` 子句中显式指定。支持的类型包括：`'none'`、`'gzip'`、`'deflate'`、`'br'`、`'xz'`、`'zstd'`、`'lz4'`、`'bz2'`。

此功能可用于[命令行客户端](/zh/concepts/features/interfaces/client)和 [clickhouse-local](/zh/concepts/features/tools-and-utilities/clickhouse-local)。

**示例**

<div id="single-file-with-from-infile">
  ### 使用 FROM INFILE 从单个文件导入数据
</div>

使用[命令行客户端](/zh/concepts/features/interfaces/client)执行以下查询：

```bash title="Query" theme={null}
echo 1,A > input.csv ; echo 2,B >> input.csv
clickhouse-client --query="CREATE TABLE table_from_file (id UInt32, text String) ENGINE=MergeTree() ORDER BY id;"
clickhouse-client --query="INSERT INTO table_from_file FROM INFILE 'input.csv' FORMAT CSV;"
clickhouse-client --query="SELECT * FROM table_from_file FORMAT PrettyCompact;"
```

```text title="Response" theme={null}
┌─id─┬─text─┐
│  1 │ A    │
│  2 │ B    │
└────┴──────┘
```

<div id="multiple-files-with-from-infile-using-globs">
  ### 使用通配符通过 FROM INFILE 处理多个文件
</div>

此示例与前一个示例非常相似，但插入操作会通过 `FROM INFILE 'input_*.csv'` 从多个文件执行。

```bash theme={null}
echo 1,A > input_1.csv ; echo 2,B > input_2.csv
clickhouse-client --query="CREATE TABLE infile_globs (id UInt32, text String) ENGINE=MergeTree() ORDER BY id;"
clickhouse-client --query="INSERT INTO infile_globs FROM INFILE 'input_*.csv' FORMAT CSV;"
clickhouse-client --query="SELECT * FROM infile_globs FORMAT PrettyCompact;"
```

<Tip>
  除了使用 `*` 选择多个文件外，你还可以使用范围 (`{1,2}` 或 `{1..9}`) 以及其他[通配符替换规则](/zh/reference/functions/table-functions/file#globs-in-path)。以下三种写法都适用于上面的示例：

  ```sql theme={null}
  INSERT INTO infile_globs FROM INFILE 'input_*.csv' FORMAT CSV;
  INSERT INTO infile_globs FROM INFILE 'input_{1,2}.csv' FORMAT CSV;
  INSERT INTO infile_globs FROM INFILE 'input_?.csv' FORMAT CSV;
  ```
</Tip>

<div id="inserting-using-a-table-function">
  ## 使用表函数进行插入
</div>

可以向由[表函数](/zh/reference/functions/table-functions)引用的表中插入数据。

**语法**

```sql theme={null}
INSERT INTO [TABLE] FUNCTION table_func ...
```

**示例**

以下查询使用了 [remote](/zh/reference/functions/table-functions/remote) 表函数：

```sql title="Query" theme={null}
CREATE TABLE simple_table (id UInt32, text String) ENGINE=MergeTree() ORDER BY id;
INSERT INTO TABLE FUNCTION remote('localhost', default.simple_table)
    VALUES (100, 'inserted via remote()');
SELECT * FROM simple_table;
```

```text title="Response" theme={null}
┌──id─┬─text──────────────────┐
│ 100 │ inserted via remote() │
└─────┴───────────────────────┘
```

<div id="inserting-into-clickhouse-cloud">
  ## 向 ClickHouse Cloud 插入数据
</div>

默认情况下，ClickHouse Cloud 中的服务会提供多个副本，以实现高可用性。当你连接到某个服务时，系统会与其中一个副本建立连接。

`INSERT` 成功后，数据会写入底层存储。不过，副本接收到这些更新可能需要一些时间。因此，如果你使用另一个连接，在其他副本上执行 `SELECT` 查询，更新后的数据可能还无法立即反映出来。

可以使用 `select_sequential_consistency` 强制副本接收最新更新。以下是一个使用此设置的 `SELECT` 查询示例：

```sql theme={null}
SELECT .... SETTINGS select_sequential_consistency = 1;
```

请注意，使用 `select_sequential_consistency` 会增加 ClickHouse Keeper (ClickHouse Cloud 在内部使用的协调服务) 的负载，并且可能会因该服务的负载情况而导致性能下降。除非确有必要，我们不建议启用此设置。推荐的做法是在同一 session 中执行读写操作，或使用采用 native protocol 的客户端驱动 (因此支持粘性连接) 。

<div id="inserting-into-a-replicated-setup">
  ## 在复制环境中插入数据
</div>

在复制环境中，数据完成复制后，才会在其他副本上可见。执行 `INSERT` 后，数据会立即开始复制 (即下载到其他副本) 。这与 ClickHouse Cloud 不同：在 ClickHouse Cloud 中，数据会立即写入共享存储，副本则通过订阅元数据变更进行同步。

请注意，在复制环境中，`INSERTs` 有时可能耗时较长 (大约为 1 秒) ，因为这需要提交到 ClickHouse Keeper 以达成分布式共识。使用 S3 作为存储也会带来额外延迟。

<div id="performance-considerations">
  ## 性能注意事项
</div>

`INSERT` 会按主键对输入数据排序，并按分区键将其拆分到不同分区中。如果一次将数据插入多个分区，`INSERT` 查询的性能可能会明显下降。为避免这种情况：

* 以较大的批次写入数据，例如每次 100,000 行。
* 在将数据上传到 ClickHouse 之前，先按分区键对数据分组。

在以下情况下，性能通常不会下降：

* 实时写入数据。
* 上传通常按时间排序的数据。

<div id="asynchronous-inserts">
  ### 异步插入
</div>

对于小而频繁的插入操作，可以采用异步插入的方式。此类插入的数据会先合并为批次，然后再安全地写入表中。要使用异步插入，请启用 [`async_insert`](/zh/reference/settings/session-settings#async_insert) 设置。

使用 `async_insert` 或 [`Buffer` 表引擎](/zh/reference/engines/table-engines/special/buffer) 都会带来额外的缓冲。

<div id="large-or-long-running-inserts">
  ### 大规模或耗时较长的插入
</div>

当插入大量数据时，ClickHouse 会通过称为“squashing”的过程来优化写入性能。内存中较小的已插入数据块会先合并并压缩成更大的块，然后再写入磁盘。squashing 可减少每次写入操作的相关开销。在此过程中，ClickHouse 每完成写入 [`max_insert_block_size`](/zh/reference/settings/session-settings#max_insert_block_size) 行后，这部分已插入的数据就可以被查询到。

**另请参见**

* [async\_insert](/zh/reference/settings/session-settings#async_insert)
* [wait\_for\_async\_insert](/zh/reference/settings/session-settings#wait_for_async_insert)
* [wait\_for\_async\_insert\_timeout](/zh/reference/settings/session-settings#wait_for_async_insert_timeout)
* [async\_insert\_max\_data\_size](/zh/reference/settings/session-settings#async_insert_max_data_size)
* [async\_insert\_busy\_timeout\_ms](/zh/reference/settings/session-settings#async_insert_busy_timeout_max_ms)
* [async\_insert\_stale\_timeout\_ms](/zh/reference/settings/session-settings#async_insert_max_data_size)
