CREATE TABLE
语句在目录中创建一个表。
Examples
创建一个包含两个整数列的表(i
和 j
):
CREATE TABLE t1 (i INTEGER, j INTEGER);
创建一个带有主键的表:
CREATE TABLE t1 (id INTEGER PRIMARY KEY, j VARCHAR);
创建一个带有复合主键的表:
CREATE TABLE t1 (id INTEGER, j VARCHAR, PRIMARY KEY (id, j));
创建一个包含各种不同类型和约束的表:
CREATE TABLE t1 (
i INTEGER NOT NULL,
decimalnr DOUBLE CHECK (decimalnr < 10),
date DATE UNIQUE,
time TIMESTAMP
);
使用CREATE TABLE ... AS SELECT
(CTAS)创建表:
CREATE TABLE t1 AS
SELECT 42 AS i, 84 AS j;
从CSV文件创建表格(自动检测列名和类型):
CREATE TABLE t1 AS
SELECT *
FROM read_csv('path/file.csv');
我们可以使用FROM
-first语法来省略SELECT *
:
CREATE TABLE t1 AS
FROM read_csv('path/file.csv');
将t2
的模式复制到t1
:
CREATE TABLE t1 AS
FROM t2
LIMIT 0;
临时表
可以使用CREATE TEMP TABLE
或CREATE TEMPORARY TABLE
语句创建临时表(见下图)。
临时表是会话范围的(例如类似于PostgreSQL),这意味着只有创建它们的特定连接才能访问它们,一旦与DuckDB的连接关闭,它们将自动删除。
临时表驻留在内存中而不是磁盘上(即使连接到持久化的DuckDB时也是如此),但如果连接时或使用SET
命令设置了temp_directory
配置,当内存受限时,数据将溢出到磁盘。
从CSV文件创建一个临时表(自动检测列名和类型):
CREATE TEMP TABLE t1 AS
SELECT *
FROM read_csv('path/file.csv');
允许临时表将多余的内存卸载到磁盘:
SET temp_directory = '/path/to/directory/';
临时表是temp.main
模式的一部分。虽然不推荐,但它们的名称可能与常规数据库表的名称重叠。在这些情况下,请使用它们的完全限定名称,例如temp.main.t1
,以消除歧义。
CREATE OR REPLACE
CREATE OR REPLACE
语法允许创建一个新表或用一个新表覆盖现有表。这是删除现有表然后创建新表的简写形式。
创建一个包含两个整数列(i 和 j)的表,即使 t1 已经存在:
CREATE OR REPLACE TABLE t1 (i INTEGER, j INTEGER);
IF NOT EXISTS
IF NOT EXISTS
语法仅在表不存在时才会继续创建表。如果表已经存在,则不会采取任何操作,现有的表将保留在数据库中。
创建一个包含两个整数列(i
和 j
)的表,仅当 t1
尚不存在时:
CREATE TABLE IF NOT EXISTS t1 (i INTEGER, j INTEGER);
CREATE TABLE ... AS SELECT
(CTAS)
DuckDB 支持 CREATE TABLE ... AS SELECT
语法,也称为“CTAS”:
CREATE TABLE nums AS
SELECT i
FROM range(0, 3) t(i);
此语法可以与CSV阅读器结合使用,直接从CSV文件中读取而不需要指定函数的简写,FROM
-first语法,以及HTTP(S)支持,产生简洁的SQL命令,如下所示:
CREATE TABLE flights AS
FROM 'https://duckdb.org/data/flights.csv';
CTAS 构造也可以与 OR REPLACE
修饰符一起使用,生成 CREATE OR REPLACE TABLE ... AS
语句:
CREATE OR REPLACE TABLE flights AS
FROM 'https://duckdb.org/data/flights.csv';
请注意,无法使用带有约束(主键、检查约束等)的CTAS语句创建表。
检查约束
一个CHECK
约束是一个表达式,必须由表中每一行的值来满足。
CREATE TABLE t1 (
id INTEGER PRIMARY KEY,
percentage INTEGER CHECK (0 <= percentage AND percentage <= 100)
);
INSERT INTO t1 VALUES (1, 5);
INSERT INTO t1 VALUES (2, -1);
Constraint Error: CHECK constraint failed: t1
INSERT INTO t1 VALUES (3, 101);
Constraint Error: CHECK constraint failed: t1
CREATE TABLE t2 (id INTEGER PRIMARY KEY, x INTEGER, y INTEGER CHECK (x < y));
INSERT INTO t2 VALUES (1, 5, 10);
INSERT INTO t2 VALUES (2, 5, 3);
Constraint Error: CHECK constraint failed: t2
CHECK
约束也可以作为 CONSTRAINTS
子句的一部分添加:
CREATE TABLE t3 (
id INTEGER PRIMARY KEY,
x INTEGER,
y INTEGER,
CONSTRAINT x_smaller_than_y CHECK (x < y)
);
INSERT INTO t3 VALUES (1, 5, 10);
INSERT INTO t3 VALUES (2, 5, 3);
Constraint Error: CHECK constraint failed: t3
外键约束
一个FOREIGN KEY
是一个列(或一组列),它引用另一个表的主键。外键检查引用完整性,即在插入时,被引用的主键必须存在于另一个表中。
CREATE TABLE t1 (id INTEGER PRIMARY KEY, j VARCHAR);
CREATE TABLE t2 (
id INTEGER PRIMARY KEY,
t1_id INTEGER,
FOREIGN KEY (t1_id) REFERENCES t1 (id)
);
示例:
INSERT INTO t1 VALUES (1, 'a');
INSERT INTO t2 VALUES (1, 1);
INSERT INTO t2 VALUES (2, 2);
Constraint Error: Violates foreign key constraint because key "id: 2" does not exist in the referenced table
可以在复合主键上定义外键:
CREATE TABLE t3 (id INTEGER, j VARCHAR, PRIMARY KEY (id, j));
CREATE TABLE t4 (
id INTEGER PRIMARY KEY, t3_id INTEGER, t3_j VARCHAR,
FOREIGN KEY (t3_id, t3_j) REFERENCES t3(id, j)
);
示例:
INSERT INTO t3 VALUES (1, 'a');
INSERT INTO t4 VALUES (1, 1, 'a');
INSERT INTO t4 VALUES (2, 1, 'b');
Constraint Error: Violates foreign key constraint because key "id: 1, j: b" does not exist in the referenced table
外键也可以在唯一列上定义:
CREATE TABLE t5 (id INTEGER UNIQUE, j VARCHAR);
CREATE TABLE t6 (
id INTEGER PRIMARY KEY,
t5_id INTEGER,
FOREIGN KEY (t5_id) REFERENCES t5(id)
);
Limitations
外键有以下限制。
不支持带有级联删除的外键(FOREIGN KEY ... REFERENCES ... ON DELETE CASCADE
)。
目前不支持插入具有自引用外键的表,这将导致以下错误:
Constraint Error: Violates foreign key constraint because key "..." does not exist in the referenced table.
生成列
[type] [GENERATED ALWAYS] AS (expr) [VIRTUAL|STORED]
语法将创建一个生成列。这种列中的数据是从其表达式中生成的,该表达式可以引用表的其他(常规或生成的)列。由于它们是通过计算生成的,因此这些列不能直接插入数据。
DuckDB 可以根据表达式的返回类型推断生成列的类型。这允许您在声明生成列时省略类型。可以显式设置类型,但如果无法将类型转换为生成列的类型,则插入引用列可能会失败。
生成的列有两种类型:VIRTUAL
和 STORED
。
虚拟生成列的数据不存储在磁盘上,而是在每次引用该列时(通过选择语句)从表达式中计算出来。
存储生成列的数据存储在磁盘上,并且每次其依赖项的数据发生变化时(通过INSERT
/ UPDATE
/ DROP
语句)都会重新计算。
目前,仅支持VIRTUAL
类型,如果最后一个字段留空,它也是默认选项。
生成列的最简单语法:
类型是从表达式中派生的,变体默认为 VIRTUAL
:
CREATE TABLE t1 (x FLOAT, two_x AS (2 * x));
为了完整性,完全指定相同的生成列:
CREATE TABLE t1 (x FLOAT, two_x FLOAT GENERATED ALWAYS AS (2 * x) VIRTUAL);