🎯 本月只剩几天支持 SQLTest.online,帮助我们让 SQL 练习对每个人都免费。 今天捐赠 →
SQL 代码已复制到剪贴板

SQL CREATE TABLE:定义表

第 9.1 课 · 阅读时间:约 9 分钟 · 练习题 ↓

SQL CREATE TABLE 语句创建一张新表:它的列、各列的数据类型,以及数据必须遵守的规则。在本课中,你将学习如何定义列、选择数据类型,以及使用主要的约束:PRIMARY KEY、NOT NULL、UNIQUE、DEFAULT、CHECK 和 FOREIGN KEY。

到目前为止,你使用的都是已经存在的表。CREATE TABLE 属于数据定义语言(DDL):这类命令定义的是数据库的结构,而不是其中的数据。设计良好的表能紧凑地存储数据、拒绝无效值,并保持表与表之间关系的一致性。

示例使用 MySQL 和 MariaDB 语法。SQLtest 上的示例数据库是只读的,因此请在练习场中选择不含示例数据的数据库来练习这些语句。

SQL CREATE TABLE:带数据类型的列名、带 AUTO_INCREMENT 的主键、NOT NULL、UNIQUE、DEFAULT 和 CHECK 约束,以及引用另一张表的外键

CREATE TABLE 语法

CREATE TABLE table_name (
    column1 data_type constraints,
    column2 data_type constraints,
    table_constraints
);

每一列都有名称、数据类型,还可以有约束和其他参数。涉及多列的约束(例如复合主键)写在所有列之后。


第一张表

CREATE TABLE students (
    student_id INT,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    birth_date DATE,
    created_at TIMESTAMP
);

结果:一张有五列的空表 students。

这张表可以使用,但它什么都接受:重复的 id、没有名字的学生。约束可以解决这些问题。


选择数据类型

数据类型存储内容示例
INT、BIGINT整数id、数量
DECIMAL(p, s)带 s 位小数的精确数值金额:DECIMAL(10, 2)
VARCHAR(n)最多 n 个字符的文本姓名、电子邮件
TEXT长文本描述
DATE日历日期出生日期
DATETIME、TIMESTAMP日期和时间创建时间
BOOLEAN真或假(MySQL 中为 TINYINT(1))标志

选择能容纳数据的最窄类型:这样既节省空间,又能拒绝错误的值。金额请存为 DECIMAL,不要用 FLOAT,因为它无法精确表示许多十进制小数。详见数据类型一课。


主键和 AUTO_INCREMENT

主键标识每一行:它的值唯一且永远不为 NULL。代理键通常由数据库通过 AUTO_INCREMENT 自动生成:

CREATE TABLE students (
    student_id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL
);

INSERT INTO students (first_name, last_name)
VALUES ('ANNA', 'LEE'), ('MARK', 'STONE');

SELECT * FROM students;

结果:两名学生,student_id 分别为自动生成的 1 和 2。

其他数据库生成键的方式不同:PostgreSQL 使用 GENERATED ALWAYS AS IDENTITY 或 SERIAL,SQL Server 使用 IDENTITY(1, 1)。


NOT NULL、UNIQUE 和 DEFAULT

CREATE TABLE employees (
    employee_id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE,
    hire_date DATE NOT NULL,
    salary DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
  • NOT NULL:该列必须有值。
  • UNIQUE:任意两行不能有相同的值。允许 NULL 值,且多个 NULL 不算重复。
  • DEFAULT:当 INSERT 没有提供值时使用的值。
-- 错误:Column 'hire_date' cannot be null
INSERT INTO employees (first_name, last_name, hire_date)
VALUES ('JOHN', 'DOE', NULL);

CHECK 约束

CHECK 定义每一行都必须满足的条件:

CREATE TABLE products (
    product_id INT AUTO_INCREMENT PRIMARY KEY,
    product_name VARCHAR(100) NOT NULL,
    price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
    discount_pct INT DEFAULT 0 CHECK (discount_pct BETWEEN 0 AND 90)
);

-- 错误:Check constraint 'products_chk_1' is violated
INSERT INTO products (product_name, price) VALUES ('Broken', -5);

MySQL 从 8.0.16 版本开始强制执行 CHECK,MariaDB 从 10.2 开始;更早的 MySQL 版本接受这种语法,但会忽略其中的条件。


外键

外键把一列与另一张表的主键关联起来。之后,数据库会拒绝被引用表中不存在的值:

CREATE TABLE departments (
    department_id INT AUTO_INCREMENT PRIMARY KEY,
    department_name VARCHAR(100) NOT NULL UNIQUE
);

CREATE TABLE staff (
    staff_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(100) NOT NULL,
    department_id INT NOT NULL,
    FOREIGN KEY (department_id) REFERENCES departments (department_id)
        ON DELETE RESTRICT
        ON UPDATE CASCADE
);

INSERT INTO departments (department_name) VALUES ('Sales');
INSERT INTO staff (full_name, department_id) VALUES ('ANNA LEE', 1);

-- 错误:a foreign key constraint fails(部门 99 不存在)
INSERT INTO staff (full_name, department_id) VALUES ('MARK STONE', 99);

ON DELETE 规定当被引用的行被删除时,子行会发生什么:

选项删除父行时
RESTRICT / NO ACTION只要还有子行,删除就会被拒绝(默认)
CASCADE子行也一起被删除
SET NULL子表中的该列被设为 NULL

当被引用的键发生变化时,ON UPDATE 的工作方式相同。Sakila 中的大多数外键使用 ON DELETE RESTRICT,这就是为什么在第 8.3 课中无法删除有租赁记录的客户。


IF NOT EXISTS

创建已经存在的表会报错。IF NOT EXISTS 会在这种情况下跳过创建,这在需要多次运行的脚本中很有用:

CREATE TABLE IF NOT EXISTS departments (
    department_id INT AUTO_INCREMENT PRIMARY KEY,
    department_name VARCHAR(100) NOT NULL
);

注意它不会比较表结构:如果同名的表已经存在但列不同,它会保持原样。


文本编码

对于文本列,MySQL 和 MariaDB 允许设置字符集和排序规则(collation):

CREATE TABLE customers (
    customer_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL
) DEFAULT CHARSET = utf8mb4;

utf8mb4 可以存储任何 Unicode 字符,包括表情符号;排序规则决定字符串如何比较和排序。从 MySQL 8.0 开始,utf8mb4 是默认字符集。


要点:

  • CREATE TABLE 定义列、数据类型和约束;新建的表是空的。
  • 选择精确的数据类型;金额使用 DECIMAL。
  • PRIMARY KEY 标识行;AUTO_INCREMENT 生成键值。
  • NOT NULL、UNIQUE、DEFAULT 和 CHECK 保证数据有效。
  • FOREIGN KEY 关联表;ON DELETE 决定子行的处理方式。
  • 表已存在时,IF NOT EXISTS 可以避免报错。

常见问题

如何在 SQL 中创建带主键的表?

给键列加上 PRIMARY KEY:CREATE TABLE students (student_id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL);。对于由多列组成的键,在列列表之后写 PRIMARY KEY (col1, col2)。

PRIMARY KEY 和 UNIQUE 有什么区别?

两者都禁止重复。一张表只能有一个主键,且主键列不能为 NULL。一张表可以有多个 UNIQUE 约束,并且它们允许 NULL 值。

如何在 CREATE TABLE 中添加外键?

在列之后写 FOREIGN KEY (column) REFERENCES other_table (key_column),还可以加上 ON DELETE 和 ON UPDATE 动作。被引用的列必须是主键或具有唯一约束。

尝试解决以下任务,以巩固您在本课中学到的内容。

  1. 创建部门表
  2. 创建企鹅统计表
  3. 创建企鹅表