4. SQL语言基础(DDL):建表、改表、删表

各位同学,今天我们来聊聊SQL里的DDL——数据定义语言。说白了,就是怎么在数据库里创建表、修改表、删除表。这部分内容我几乎每天都在用,从第一行代码写到项目上线,DDL是绕不开的基本功。

我记得刚入行那会儿,有个同事建表时没加主键约束,结果数据一多,查起来慢得像蜗牛爬。后来被DBA叫去喝茶,回来老老实实补了主键。嗯,这个坑我替你们踩过了,今天咱们就一次性把DDL讲透。

DDL核心三件事:

  • CREATE TABLE —— 建表
  • ALTER TABLE —— 改表
  • DROP TABLE —— 删表
DDL 核心知识体系 DDL CREATE TABLE 数据类型 + 约束 ALTER TABLE ADD / DROP / MODIFY DROP TABLE 删除表结构+数据 DDL 操作后自动提交事务,不可回滚! Android 中通过 SQLiteOpenHelper 的 onCreate / onUpgrade 管理

4.1 CREATE TABLE —— 建表语句

建表是DDL的第一步。语法其实很简单,但细节决定成败。我个人习惯在写CREATE TABLE之前,先在纸上画一下表结构,想清楚字段类型和约束,再动手写SQL。

基本语法长这样:

CREATE TABLE 表名 (
    列名1 数据类型 约束,
    列名2 数据类型 约束,
    ...
);

举个例子,创建一个用户表:

CREATE TABLE user (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL,
    age INTEGER DEFAULT 18,
    created_at TEXT DEFAULT (datetime('now'))
);

我在项目中遇到过一个问题:有同事建表时忘了加AUTOINCREMENT,结果插入数据时主键冲突,导致应用崩溃。你想想看,这种低级错误其实完全可以避免,只要养成习惯——每个表都明确指定主键和自增策略。

4.2 数据类型

SQLite的数据类型和其他数据库不太一样。它只有五种存储类,我列个表给你看:

存储类 说明 示例
NULL 空值 NULL
INTEGER 整型,1-8字节 42, -100
REAL 浮点型,8字节 3.14, -0.5
TEXT 文本字符串 'hello', '张三'
BLOB 二进制数据 图片、文件等

小提示:SQLite有个"类型亲和性"的概念。比如你声明VARCHAR(100),它其实会转成TEXT。所以别纠结于长度限制,SQLite不强制检查。我一般直接用TEXT、INTEGER、REAL这三种,够用了。

4.3 约束

约束就是给字段加规则。没有约束的表,就像没有交通规则的路——数据想怎么填就怎么填,最后乱成一锅粥。

PRIMARY KEY(主键)

主键唯一标识一行记录。每个表只能有一个主键,但可以是多个字段的组合(复合主键)。

-- 单字段主键
CREATE TABLE student (
    id INTEGER PRIMARY KEY,
    name TEXT
);

-- 复合主键
CREATE TABLE score (
    student_id INTEGER,
    course_id INTEGER,
    score REAL,
    PRIMARY KEY (student_id, course_id)
);

NOT NULL(非空)

这个约束很简单——字段不能为空。我曾经接手过一个项目,用户表的email字段没加NOT NULL,结果注册时有人没填邮箱,后续发通知全崩了。从那以后,凡是业务上必填的字段,我一定加NOT NULL。

CREATE TABLE product (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,       -- 商品名不能为空
    price REAL NOT NULL       -- 价格不能为空
);

UNIQUE(唯一)

保证字段值不重复。比如用户名、邮箱、身份证号这些,天然就应该唯一。

CREATE TABLE account (
    id INTEGER PRIMARY KEY,
    username TEXT UNIQUE NOT NULL,
    email TEXT UNIQUE NOT NULL
);

注意:UNIQUE和PRIMARY KEY的区别在于:主键自带唯一性,且不能为NULL;UNIQUE允许NULL值(但SQLite中多个NULL不算重复)。另外,一个表可以有多个UNIQUE约束,但只能有一个PRIMARY KEY。

4.4 ALTER TABLE —— 修改表结构

项目上线后,需求变了怎么办?改表!ALTER TABLE就是干这个的。不过SQLite的ALTER TABLE功能比较弱,只支持三种操作:

  • 重命名表
  • 添加列
  • 重命名列(SQLite 3.25.0+)

不支持删除列、修改列类型等操作。嗯,这个限制我刚开始用的时候也很不爽,但后来习惯了——反正有变通办法。

添加列:

ALTER TABLE user ADD COLUMN phone TEXT;

注意:新加的列不能有NOT NULL约束(除非指定了默认值)。

重命名表:

ALTER TABLE old_table RENAME TO new_table;

重命名列:

ALTER TABLE user RENAME COLUMN phone TO mobile;

避坑指南:我曾经在项目中需要删除一个列,但SQLite不支持。怎么办?我的做法是:

  1. 创建新表(不含要删除的列)
  2. INSERT INTO 新表 SELECT 需要的列 FROM 旧表
  3. DROP TABLE 旧表
  4. ALTER TABLE 新表 RENAME TO 旧表名

虽然步骤多了点,但数据安全第一。

4.5 DROP TABLE —— 删除表

删表是最危险的操作之一。语法很简单:

DROP TABLE 表名;

比如:

DROP TABLE user;

执行之后,表结构和数据全部消失,无法恢复。为什么?因为DDL操作会自动提交事务,没有回滚的机会。

警告:生产环境千万别直接DROP TABLE!我见过有人手滑把用户表删了,结果恢复数据花了两天。如果你只是想清空数据,用DELETE FROM 表名;如果想保留表结构只删数据,用TRUNCATE(但SQLite不支持TRUNCATE,可以用DELETE FROM 表名 + VACUUM)。

另外,如果你在Android的SQLiteOpenHelper里升级数据库,一般不会直接DROP TABLE,而是通过版本号判断,执行ALTER TABLE或者重建表。这个后面章节会详细讲。

4.6 综合示例

最后,我写一个完整的例子,把今天讲的内容串起来:

-- 1. 建表
CREATE TABLE employee (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    department TEXT NOT NULL,
    salary REAL DEFAULT 0,
    hire_date TEXT
);

-- 2. 添加新列
ALTER TABLE employee ADD COLUMN email TEXT UNIQUE;

-- 3. 重命名列
ALTER TABLE employee RENAME COLUMN salary TO monthly_salary;

-- 4. 删除表(慎用!)
-- DROP TABLE employee;

好了,DDL的基础内容就这些。建表、改表、删表,每个操作都有它的使用场景和注意事项。我个人建议你在写任何DDL之前,先想清楚业务需求,再动手。毕竟数据库结构一旦定下来,后面改起来就麻烦了。

记住一句话:好的表结构设计,能让后续开发事半功倍;糟糕的表结构,会让你天天加班改Bug。嗯,我深有体会。


公众号:蓝海资料掘金营,微信deep3321