4. SQL语言基础(DDL):建表、改表、删表
各位同学,今天我们来聊聊SQL里的DDL——数据定义语言。说白了,就是怎么在数据库里创建表、修改表、删除表。这部分内容我几乎每天都在用,从第一行代码写到项目上线,DDL是绕不开的基本功。
我记得刚入行那会儿,有个同事建表时没加主键约束,结果数据一多,查起来慢得像蜗牛爬。后来被DBA叫去喝茶,回来老老实实补了主键。嗯,这个坑我替你们踩过了,今天咱们就一次性把DDL讲透。
DDL核心三件事:
- CREATE TABLE —— 建表
- ALTER TABLE —— 改表
- DROP TABLE —— 删表
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不支持。怎么办?我的做法是:
- 创建新表(不含要删除的列)
- INSERT INTO 新表 SELECT 需要的列 FROM 旧表
- DROP TABLE 旧表
- 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