SQLite数据删除 #
一、DELETE语句概述 #
1.1 基本语法 #
sql
-- DELETE 基本语法
DELETE FROM table_name
WHERE condition;
-- 示例表结构
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE,
status INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO users (name, email, status) VALUES
('John', 'john@example.com', 1),
('Jane', 'jane@example.com', 1),
('Bob', 'bob@example.com', 0),
('Alice', 'alice@example.com', 0),
('Charlie', 'charlie@example.com', 1);
1.2 删除特点 #
sql
-- SQLite DELETE 特点:
-- 1. 可以删除单行或多行
-- 2. 支持子查询条件
-- 3. 支持 RETURNING 子句(3.35+)
-- 4. 不支持 LIMIT(需要变通)
-- 5. 触发 DELETE 触发器
二、基本删除 #
2.1 条件删除 #
sql
-- 删除指定行
DELETE FROM users WHERE id = 1;
-- 删除多行
DELETE FROM users WHERE status = 0;
-- 删除所有行(危险!)
DELETE FROM users;
2.2 使用比较运算符 #
sql
-- 等于
DELETE FROM users WHERE id = 1;
-- 不等于
DELETE FROM users WHERE status != 1;
-- 大于/小于
DELETE FROM users WHERE id > 100;
DELETE FROM users WHERE created_at < date('now', '-30 days');
-- 范围
DELETE FROM users WHERE id BETWEEN 1 AND 10;
2.3 使用逻辑运算符 #
sql
-- AND
DELETE FROM users
WHERE status = 0 AND created_at < date('now', '-30 days');
-- OR
DELETE FROM users
WHERE status = 0 OR created_at < date('now', '-365 days');
-- NOT
DELETE FROM users
WHERE NOT status = 1;
2.4 使用IN和NOT IN #
sql
-- IN
DELETE FROM users WHERE id IN (1, 2, 3);
-- NOT IN
DELETE FROM users WHERE status NOT IN (1, 2);
-- 子查询
DELETE FROM users
WHERE id IN (SELECT user_id FROM inactive_users);
2.5 使用LIKE #
sql
-- LIKE 模式匹配
DELETE FROM users WHERE email LIKE '%@old-domain.com';
-- GLOB 模式匹配
DELETE FROM users WHERE email GLOB '*@test.*';
三、子查询删除 #
3.1 使用子查询条件 #
sql
-- 删除没有订单的用户
DELETE FROM users
WHERE id NOT IN (SELECT DISTINCT user_id FROM orders);
-- 删除有特定条件的记录
DELETE FROM users
WHERE id IN (
SELECT user_id
FROM orders
WHERE total < 10
);
-- 使用EXISTS
DELETE FROM users
WHERE NOT EXISTS (
SELECT 1 FROM orders WHERE orders.user_id = users.id
);
3.2 复杂子查询删除 #
sql
-- 删除超过一定时间未活跃的用户
DELETE FROM users
WHERE id IN (
SELECT u.id
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.order_date IS NULL
OR o.order_date < date('now', '-365 days')
);
-- 删除重复记录(保留最新的一条)
DELETE FROM logs
WHERE id NOT IN (
SELECT MAX(id)
FROM logs
GROUP BY user_id, action
);
四、RETURNING子句 #
4.1 返回删除数据 (SQLite 3.35.0+) #
sql
-- 返回被删除的数据
DELETE FROM users
WHERE id = 1
RETURNING id, name, email;
-- 返回所有列
DELETE FROM users
WHERE status = 0
RETURNING *;
-- 返回计算值
DELETE FROM users
WHERE id = 1
RETURNING
id,
name,
'deleted' AS action,
datetime('now') AS deleted_at;
4.2 批量删除返回 #
sql
-- 批量删除并返回
DELETE FROM users
WHERE status = 0
RETURNING id, name;
-- 查看删除的行数
SELECT changes();
五、级联删除 #
5.1 外键级联删除 #
sql
-- 启用外键约束
PRAGMA foreign_keys = ON;
-- 创建带级联删除的表
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER,
total REAL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE order_items (
id INTEGER PRIMARY KEY,
order_id INTEGER,
product_id INTEGER,
quantity INTEGER,
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE
);
-- 删除用户时,自动删除相关订单和订单项
DELETE FROM users WHERE id = 1;
5.2 级联删除选项 #
sql
-- CASCADE:级联删除
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- SET NULL:设置为NULL
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
);
-- SET DEFAULT:设置为默认值
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER DEFAULT 0,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET DEFAULT
);
-- RESTRICT:限制删除(默认)
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT
);
-- NO ACTION:无动作(同RESTRICT)
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION
);
5.3 手动级联删除 #
sql
-- 如果没有设置级联,需要手动删除
BEGIN TRANSACTION;
-- 先删除子表记录
DELETE FROM order_items
WHERE order_id IN (SELECT id FROM orders WHERE user_id = 1);
DELETE FROM orders WHERE user_id = 1;
-- 最后删除主表记录
DELETE FROM users WHERE id = 1;
COMMIT;
六、TRUNCATE模拟 #
6.1 SQLite没有TRUNCATE #
sql
-- SQLite 不支持 TRUNCATE TABLE
-- TRUNCATE TABLE users; -- 错误!
-- 替代方案1:DELETE
DELETE FROM users;
-- 替代方案2:删除并重建表
DROP TABLE users;
CREATE TABLE users (...);
-- 替代方案3:使用DELETE + VACUUM
DELETE FROM users;
VACUUM;
6.2 清空表对比 #
sql
-- 方法1:DELETE FROM
-- 优点:触发触发器
-- 缺点:较慢,不重置ROWID
DELETE FROM users;
-- 方法2:DROP + CREATE
-- 优点:快速,重置ROWID
-- 缺点:需要重建索引、触发器
DROP TABLE users;
CREATE TABLE users (...);
CREATE INDEX ...;
-- 方法3:DELETE + VACUUM
-- 优点:回收空间
-- 缺点:最慢
DELETE FROM users;
VACUUM;
七、软删除 #
7.1 实现软删除 #
sql
-- 添加删除标记列
ALTER TABLE users ADD COLUMN deleted_at DATETIME;
-- 软删除:更新deleted_at
UPDATE users
SET deleted_at = CURRENT_TIMESTAMP
WHERE id = 1;
-- 查询时排除已删除记录
SELECT * FROM users WHERE deleted_at IS NULL;
-- 恢复删除
UPDATE users
SET deleted_at = NULL
WHERE id = 1;
7.2 使用视图简化 #
sql
-- 创建视图只显示未删除记录
CREATE VIEW active_users AS
SELECT id, name, email, status
FROM users
WHERE deleted_at IS NULL;
-- 使用视图
SELECT * FROM active_users;
-- 通过视图操作
INSERT INTO active_users (name, email) VALUES ('Test', 'test@example.com');
UPDATE active_users SET status = 0 WHERE id = 1;
-- 注意:DELETE 不能直接通过视图软删除
7.3 使用触发器自动软删除 #
sql
-- 创建触发器拦截DELETE操作
CREATE TRIGGER users_soft_delete
INSTEAD OF DELETE ON users
BEGIN
UPDATE users
SET deleted_at = CURRENT_TIMESTAMP
WHERE id = OLD.id AND deleted_at IS NULL;
END;
-- 现在DELETE操作变成软删除
DELETE FROM users WHERE id = 1;
-- 实际执行的是 UPDATE users SET deleted_at = ... WHERE id = 1
八、LIMIT删除 #
8.1 SQLite不支持DELETE LIMIT #
sql
-- SQLite 不支持这种语法
-- DELETE FROM users WHERE status = 0 LIMIT 10; -- 错误!
8.2 变通方法 #
sql
-- 使用子查询实现LIMIT删除
DELETE FROM users
WHERE id IN (
SELECT id FROM users
WHERE status = 0
LIMIT 10
);
-- 分批删除大量数据
-- 每次删除1000条
DELETE FROM logs
WHERE id IN (
SELECT id FROM logs
WHERE created_at < date('now', '-365 days')
LIMIT 1000
);
-- 重复执行直到删除完成
九、删除性能优化 #
9.1 批量删除优化 #
sql
-- 使用事务
BEGIN TRANSACTION;
DELETE FROM logs WHERE created_at < date('now', '-30 days');
COMMIT;
-- 分批删除大量数据
BEGIN TRANSACTION;
DELETE FROM logs
WHERE id IN (
SELECT id FROM logs
WHERE created_at < date('now', '-365 days')
LIMIT 10000
);
COMMIT;
-- 重复执行
-- 临时禁用索引
-- SQLite不支持DISABLE INDEX
-- 可以先删除索引,删除后再创建
9.2 删除后优化 #
sql
-- 删除大量数据后执行VACUUM
DELETE FROM logs WHERE created_at < date('now', '-365 days');
VACUUM;
-- 更新统计信息
ANALYZE;
十、安全考虑 #
10.1 防止意外删除 #
sql
-- 错误:忘记WHERE条件
DELETE FROM users; -- 删除所有行!
-- 安全做法:先查询
SELECT COUNT(*) FROM users WHERE status = 0;
-- 确认后再执行删除
-- 使用事务
BEGIN TRANSACTION;
DELETE FROM users WHERE status = 0;
-- 检查结果
SELECT changes();
-- 确认无误后提交
COMMIT;
-- 或回滚
ROLLBACK;
10.2 备份重要数据 #
sql
-- 删除前备份
CREATE TABLE users_backup AS SELECT * FROM users WHERE status = 0;
-- 或导出到文件
-- .output users_to_delete.sql
-- SELECT 'INSERT INTO users VALUES(' || id || ',' || quote(name) || ');'
-- FROM users WHERE status = 0;
-- .output stdout
10.3 参数化查询 #
sql
-- 使用参数化查询
-- Python
-- cursor.execute("DELETE FROM users WHERE id = ?", (user_id,))
-- PHP
-- $stmt = $pdo->prepare("DELETE FROM users WHERE id = ?");
-- $stmt->execute([$user_id]);
十一、删除触发器 #
11.1 DELETE触发器 #
sql
-- 创建删除触发器
CREATE TRIGGER users_delete_log
AFTER DELETE ON users
BEGIN
INSERT INTO users_log (user_id, action, action_time)
VALUES (OLD.id, 'DELETE', CURRENT_TIMESTAMP);
END;
-- 触发器会在DELETE时自动执行
DELETE FROM users WHERE id = 1;
-- 自动记录到 users_log
11.2 使用OLD引用 #
sql
-- 在触发器中使用OLD引用被删除的行
CREATE TRIGGER orders_delete_archive
BEFORE DELETE ON orders
BEGIN
INSERT INTO orders_archive (
order_id, user_id, total, deleted_at
)
VALUES (
OLD.id, OLD.user_id, OLD.total, CURRENT_TIMESTAMP
);
END;
十二、常见问题 #
12.1 外键约束错误 #
sql
-- 启用外键
PRAGMA foreign_keys = ON;
-- 错误:FOREIGN KEY constraint failed
DELETE FROM users WHERE id = 1;
-- 因为 orders 表有引用
-- 解决方案:
-- 1. 先删除子表记录
DELETE FROM orders WHERE user_id = 1;
DELETE FROM users WHERE id = 1;
-- 2. 或使用级联删除
-- 创建表时指定 ON DELETE CASCADE
12.2 删除0行 #
sql
-- 删除返回0行
DELETE FROM users WHERE id = 999;
-- 检查影响的行数
SELECT changes(); -- 返回0
-- 解决方案:确认条件是否正确
SELECT * FROM users WHERE id = 999;
12.3 触发器阻止删除 #
sql
-- 触发器可能阻止删除
CREATE TRIGGER prevent_delete
BEFORE DELETE ON users
BEGIN
SELECT RAISE(ABORT, 'Cannot delete users');
END;
-- 删除会失败
DELETE FROM users WHERE id = 1;
-- Error: Cannot delete users
十三、总结 #
删除方法对比 #
| 方法 | 语法 | 说明 |
|---|---|---|
| 条件删除 | DELETE FROM … WHERE | 删除符合条件的行 |
| 全表删除 | DELETE FROM | 删除所有行 |
| 子查询删除 | WHERE id IN (SELECT …) | 基于子查询删除 |
| 级联删除 | ON DELETE CASCADE | 自动删除关联记录 |
| 软删除 | UPDATE SET deleted_at | 标记为已删除 |
最佳实践 #
- 始终使用WHERE条件(除非确实要删除所有行)
- 使用事务包装重要删除操作
- 先查询确认再删除
- 考虑使用软删除保留数据
- 使用RETURNING获取删除结果
下一步,让我们学习基础查询操作!
最后更新:2026-03-27