跳到主要内容

CREATE TABLE

Introduced or updated: v1.2.953
企业版功能
COMPUTED COLUMN是企业版功能。 如需获取许可证,请联系 Databend 支持团队。

在许多数据库中,创建表是最复杂的操作之一,因为你可能需要:

  • 手动指定引擎
  • 手动指定索引
  • 甚至指定数据分区或分片

Databend 以“开箱即用”为设计目标,创建表时无需上述任何操作。此外,CREATE TABLE 语句提供以下选项,帮助你在不同场景下轻松建表:

另请参阅:

CREATE TABLE​

CREATE [ OR REPLACE ] TABLE [ IF NOT EXISTS ] [ <database_name>. ]<table_name>
(
<column_name> <data_type> [ NOT NULL | NULL ]
[ { DEFAULT <expr>
| { AUTOINCREMENT | IDENTITY }
[ { ( <start_num> , <step_num> )
| START <num> INCREMENT <num> } ]
[ { ORDER | NOORDER } ]
} ]
[ AS (<expr>) STORED | VIRTUAL ]
[ COMMENT '<comment>' ],
<column_name> <data_type> ...
...
)
[ ENGINE = FUSE ]
[ PARTITION BY ( <expr> [ , <expr> ... ] ) ]
[ CLUSTER BY ( <expr> [ , <expr> ... ] ) ]
[ TTL <ttl_expression> ]
[ <fuse_engine_option> = <value> ... ]

行级 TTL​

TTL 定义行何时过期。TTL 定义本身不会调度清理任务。请使用 ALTER TABLE ... MATERIALIZE TTL 显式删除过期行。手动清理命令及以下表达式规则在 v1.2.953 中可用。

CREATE TABLE retained_events (
id INT,
event_time TIMESTAMP
) TTL event_time + INTERVAL 30 DAY;

TTL 表达式必须使用以下形式之一:

  • <time_column>:指定绝对过期时间。
  • <time_column> + INTERVAL <nonnegative_integer> <unit>:指定保留时长。

列类型必须为 DATE、TIMESTAMP 或 TIMESTAMP_TZ。支持可空列和 STORED 计算列,不支持 VIRTUAL 计算列。支持的时间间隔单位为 MICROSECOND、SECOND、MINUTE、HOUR、DAY、WEEK、MONTH、QUARTER 和 YEAR。

请使用不带限定符的列名,以及不加引号的非负整数间隔。常量时间戳、函数调用、类型转换、多列表达式、负数间隔,以及 INTERVAL '30' DAY 这样的字符串间隔,都不是有效的定义。

TTL 仅支持持久化 Fuse 表。临时表和瞬态表不支持 TTL。SHOW CREATE TABLE 会包含已存储的 TTL 定义。通过查询创建表时,也可以在 AS SELECT 之前指定 TTL。

有关截止时间比较、权限、安全策略行为和示例,请参阅行级 TTL。

Fuse 表分区​

PARTITION BY 使用一个或多个分区表达式对 Fuse 表进行物理隔离。Databend 会在写入和维护操作中保留分区边界,并通过分区元数据在扫描前裁剪无关数据。

CREATE TABLE events (
event_id BIGINT,
event_time TIMESTAMP,
tenant_id BIGINT
)
PARTITION BY (DATE_TRUNC(day, event_time))
CLUSTER BY (tenant_id, event_time);

每个表达式必须是确定性的,并且只能引用一个源列。复合分区键需要分别列出多个表达式:

PARTITION BY (DATE_TRUNC(month, event_time), BUCKET(16, tenant_id))

对于高基数键,BUCKET() 可将其映射到固定数量的哈希分区。WRITE_DISTRIBUTION_MODE = 'hash' 还能在分布式导入时,将分区值相同的行路由到同一个 Writer:

CREATE TABLE customer_events (
customer_id BIGINT,
event_time TIMESTAMP
)
PARTITION BY (BUCKET(32, customer_id))
WRITE_DISTRIBUTION_MODE = 'hash';

哈希写入模式必须与 PARTITION BY 一同使用,默认值为 'none'。有关分区策略、限制和完整示例,请参见 Fuse 表分区。

备注
  • 关于 Databend 支持的数据类型,参见 数据类型。
  • 建议列名避免特殊字符;如必须使用,请用反引号包裹,例如:CREATE TABLE price(`$CA` int);
  • Databend 会自动将列名转为小写。例如列名 Total 在结果中显示为 total。

CREATE TABLE ... LIKE​

按已有表的列定义创建新表,复制列名、数据类型及非 NULL 约束,但不复制数据及其他属性(如 CLUSTER BY、TRANSIENT、COMPRESSION)。

语法:

CREATE TABLE [IF NOT EXISTS] [db.]table_name
LIKE [db.]origin_table_name
解决方法

可显式指定 TRANSIENT 或 COMPRESSION:

create transient table t_new like t_old;
create table t_new compression='lz4' like t_old;

CREATE TABLE ... AS​

创建表并用 SELECT 查询结果填充数据,不继承原表的任何属性(如 CLUSTER BY、TRANSIENT、COMPRESSION)。

语法:

CREATE TABLE [IF NOT EXISTS] [db.]table_name
AS SELECT query
解决方法

可显式指定 TRANSIENT 或 COMPRESSION:

create transient table t_new as select * from t_old;
create table t_new compression='lz4' as select * from t_old;

列的可空性​

默认情况下,所有列都允许 NULL。如需禁止 NULL,请使用 NOT NULL 约束。详见 NULL 值与 NOT NULL 约束。

列默认值​

DEFAULT <expr> 为列设置默认值,支持:

  • 固定常量,如 Marketing
  • 无入参的标量表达式,如 1 + 1、NOW()、UUID()
  • 序列动态值,如 NEXTVAL(staff_id_seq)
    • NEXTVAL 必须独立使用,不支持 NEXTVAL(seq1) + 1
    • 需具备相应序列权限

自增列​

Introduced or updated: v1.2.821

使用 AUTOINCREMENT 或 IDENTITY 创建自增列,自动生成顺序数字,常用于唯一标识。

语法:

{ AUTOINCREMENT | IDENTITY }
[ { ( <start_num> , <step_num> )
| START <num> INCREMENT <num> } ]
[ { ORDER | NOORDER } ]

参数:

  • start_num:起始值(默认 1)
  • step_num:步长(默认 1)
  • ORDER:保证单调递增(可能有间隙)
  • NOORDER:不保证顺序(默认)

要点:

  • 内部由序列实现
  • 删除列时关联序列一并删除
  • 未指定值时自动生成
  • AUTOINCREMENT 与 IDENTITY 等价

示例:

CREATE TABLE users (
user_id BIGINT AUTOINCREMENT,
order_id BIGINT AUTOINCREMENT START 100 INCREMENT 10,
username VARCHAR
);

INSERT INTO users (username) VALUES ('alice'), ('bob'), ('charlie');

SELECT * FROM users;

计算列​

计算列通过标量表达式由其他列生成,支持两种类型:

  • STORED:值持久化存储,依赖列变更时自动更新
  • VIRTUAL:查询时实时计算,节省存储

语法:

<column_name> <data_type> [ NOT NULL | NULL ] AS (<expr>) { STORED | VIRTUAL }
<column_name> <data_type> [ NOT NULL | NULL ] GENERATED ALWAYS AS (<expr>) { STORED | VIRTUAL }

示例:

-- STORED:物理存储,立即更新
CREATE TABLE products (
id INT,
price FLOAT64,
quantity INT,
total_price FLOAT64 AS (price * quantity) STORED
);

-- VIRTUAL:查询时计算,无存储开销
CREATE TABLE employees (
id INT,
first_name VARCHAR,
last_name VARCHAR,
full_name VARCHAR AS (CONCAT(first_name, ' ', last_name)) VIRTUAL
);
提示

频繁查询且对性能敏感时选 STORED;计算成本可接受且需节省空间时选 VIRTUAL。

持久化表达式限制​

Introduced or updated: v1.2.952

从 v1.2.952 开始,Databend 验证以下定义时会拒绝依赖会话或查询上下文的函数:

  • 计算列,包括 STORED 和 VIRTUAL。
  • CLUSTER BY 和 PARTITION BY 表达式。
  • 表 TTL 表达式。

存储层过滤器也采用此受限验证。这并不意味着每个普通查询的 WHERE 子句都受此限制。

不要在这些表达式中使用 current_database()、current_user()、角色函数、getvariable() / $var、last_query_id() 或 timezone()。将上下文函数嵌套在其他函数中也无效。Databend 会在它被折叠为字面量之前拒绝该函数。

用户定义函数也不允许使用,包括纯 SQL UDF。例如,即使 UDF 仅将输入值加一,也不能用于计算列定义。缓存中的 UDF 定义同样无法绕过此限制。

array_sort() 必须显式指定 NULL 排序顺序。array_sort(a) 和 array_sort(a, 'asc') 都依赖会话的默认 NULL 排序顺序,因此会在这些定义中被拒绝。请使用三个参数,例如 array_sort(a, 'asc', 'nulls last')。

-- Rejected: the computed expression reads session context.
CREATE TABLE invalid_context(
a STRING,
b STRING AS (concat(a, current_database())) STORED
);

-- Rejected: the null order depends on a session setting.
CREATE TABLE invalid_sort(
a ARRAY(INT),
b ARRAY(INT) AS (array_sort(a)) STORED
);

-- Explicit null ordering passes this context check.
-- Creating a computed column still requires an Enterprise license.
CREATE TABLE explicit_sort(
a ARRAY(INT),
b ARRAY(INT) AS (array_sort(a, 'asc', 'nulls last')) STORED
);

请使用满足各功能其他规则的确定性内置表达式。分区表达式仍必须仅引用一个源列。TTL 的语法和类型限制仍然有效。

这些检查并不保证每种类型转换或表达式都独立于会话设置。例如,普通的时区敏感类型转换仍使用捕获的函数上下文。已有存储键保留兼容性重绑定;此变更不是对现有键定义的迁移。

列的 DEFAULT 表达式使用独立的验证路径。它们仍可以使用上下文函数,例如 DEFAULT current_user()。

MySQL 兼容性​

Databend 语法与 MySQL 的差异主要在数据类型及部分索引提示。

与 MySQL 不同,Databend 默认采用 PostgreSQL 风格的标识符大小写规则:未引用的列名会被转换为小写,而双引号包裹的列名则保留原始大小写且区分大小写。因此,如果建表时使用了保留大小写的引用列名(例如 "Employee_ID"),SELECT * 可以正常返回数据,但 SELECT Employee_ID 或 SELECT employee_id 会失败。有关大小写规则、相关设置以及如何排查此类问题,请参阅 SQL 标识符。

访问控制要求​

权限对象类型描述
CREATE全局、表创建表

创建表时,用户或 current_role 需具备 CREATE 权限。

使用 STORAGE_PREFIX 的 CREATE TABLE 还需要在目标数据库级或全局拥有显式的 ATTACH TABLE 权限。CREATE、SUPER 和数据库所有权均不包含此额外权限。不使用 STORAGE_PREFIX 的普通建表操作不需要该权限。参见 ATTACH TABLE。

示例​

创建表​

创建带默认值的表:

CREATE TABLE books (
id BIGINT UNSIGNED,
title VARCHAR,
genre VARCHAR DEFAULT 'General'
);

查看表结构:

DESC books;

插入数据:

INSERT INTO books(id, title) VALUES(1, 'Invisible Stars');

查询结果:

SELECT * FROM books;

CREATE TABLE ... LIKE​

按结构创建新表:

CREATE TABLE books_copy LIKE books;

CREATE TABLE ... AS​

创建并复制数据:

CREATE TABLE books_backup AS SELECT * FROM books;

计算列示例​

CREATE TABLE IF NOT EXISTS products (
id INT,
price FLOAT64,
quantity INT,
total_price FLOAT64 AS (price * quantity) STORED
);

INSERT INTO products VALUES (1,10.5,3),(2,15.2,5),(3,8.7,2);

SELECT * FROM products;
CREATE TABLE student_profiles (
id STRING,
profile VARIANT,
age INT NULL AS (profile['age']::INT) VIRTUAL
);

INSERT INTO student_profiles VALUES
('d78236','{"id":"d78236","name":"Arthur Read","age":"16"}'),
('f98112','{"name":"Buster Bunny","age":"15","id":"f98112"}'),
('t63512','{"name":"Ernie Narayan","id":"t63512"}');

SELECT * FROM student_profiles;
欢迎体验 Databend Cloud

基于 Rust + 对象存储构建的新一代多模态数仓,一个平台即可进行 BI、向量、全文检索及地理空间分析。

支持标准 SQL,自动弹性伸缩,助您快速构建现代化数据平台。

注册即领 ¥200 代金券。

注册体验