SQLite实现反向级联删除:删除全部关联歌曲时自动删除电影条目
在SQLite实现一对多关系的反向级联删除
SQLite本身没有原生支持这种“当子表所有关联记录删除后自动删除父表记录”的反向级联,但用**触发器(Trigger)**就能完美实现这个需求,操作起来和常规级联删除一样简便。下面一步步来:
1. 先确认你的表结构(示例)
假设你的表结构大概是这样的(如果和实际有出入,调整字段名即可):
-- 创建movies表(父表) CREATE TABLE movies ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL ); -- 创建songs表(子表),movie_id是关联movies的外键 CREATE TABLE songs ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, movie_id INTEGER NOT NULL, FOREIGN KEY (movie_id) REFERENCES movies(id) ON DELETE CASCADE -- 可选:如果需要删电影时自动删歌曲,保留这个;不需要就去掉 );
2. 开启SQLite外键约束
SQLite默认是关闭外键约束的,所以先执行这条语句确保外键生效(不然你的外键关联可能不起作用):
PRAGMA foreign_keys = ON;
3. 创建核心触发器
我们需要在songs表上创建一个AFTER DELETE触发器,每次删除歌曲后,检查对应的电影是否还有关联的歌曲。如果没有,就自动删除该电影记录:
CREATE TRIGGER delete_movie_when_no_songs_left AFTER DELETE ON songs FOR EACH ROW BEGIN -- 检查当前电影是否还有剩余的歌曲 SELECT COUNT(*) INTO @song_count FROM songs WHERE movie_id = OLD.movie_id; -- 如果歌曲数量为0,删除对应的电影 IF @song_count = 0 THEN DELETE FROM movies WHERE id = OLD.movie_id; END IF; END;
触发器逻辑解释:
AFTER DELETE ON songs:指定触发时机是在songs表的记录被删除之后FOR EACH ROW:每删除一条歌曲记录就执行一次触发器逻辑OLD.movie_id:代表被删除的那条歌曲记录关联的电影ID- 先统计该电影剩余的歌曲数量,若为0则删除对应的电影记录
4. 测试验证
举个简单的测试流程:
- 插入一部电影和两首歌曲:
INSERT INTO movies (title) VALUES ('肖申克的救赎'); INSERT INTO songs (name, movie_id) VALUES ('主题音乐', 1), ('片尾插曲', 1);
- 删除其中一首歌曲:
DELETE FROM songs WHERE name = '主题音乐';
此时songs表还剩一首关联歌曲,movies表的记录会保留。
3. 删除最后一首歌曲:
DELETE FROM songs WHERE name = '片尾插曲';
此时触发器会检测到该电影没有剩余歌曲,自动删除movies表中对应的记录。
补充说明
- 如果是批量删除同一电影的所有歌曲,触发器会在每条记录删除后执行检查,最后一次检查时歌曲数量为0,同样会触发电影删除,逻辑依然有效。
- 如果你不需要“删电影自动删歌曲”的正向级联,可以去掉
songs表外键定义里的ON DELETE CASCADE,不影响反向触发器的功能。
内容的提问来源于stack exchange,提问作者Nandu
相关产品推荐
相关产品推荐

