🐸 青蛙编程网
首页 / 数据库 / SQLite / 7. 多表查询与外键

7. 多表查询与外键

这是什么:JOIN = 查询时把两张表按条件拼起来,一次拿到「文章 + 作者名」这样的组合信息;外键(FOREIGN KEY)= 声明「这一列的值必须在另一张表里存在」。

为什么用:文章表里只存了 user_id,可页面上要显示作者名——数据分家了,查询时就得把它们重新拼上。而 SQLite 有个新手第一大坑:外键默认是关的,不打开就形同虚设。

如何用:先 JOIN 连表查询,再专门开一节收拾外键这个坑。

7.1 JOIN:文章带作者名

SELECT u.username, a.title, a.views
FROM article a
JOIN user u ON a.user_id = u.id
ORDER BY a.views DESC;

预期输出(沿用前几章的数据):

frog|从零学前端:HTML 入门|130
frog|CSS 才是网页的灵魂|85

article a 给表起短别名;ON a.user_id = u.id 说明两表怎么对上号。写法与 MySQL 的 JOIN 完全相同,LEFT JOIN 也一样可用(上一章已经用过了)。

7.2 大坑预警:外键默认关闭

第 3 章建 article 表时写了 REFERENCES user(id),但现在试试往里塞一个不存在的作者:

INSERT INTO article (title, views, user_id) VALUES ('幽灵文章', 1, 999);
SELECT COUNT(*) FROM article WHERE user_id = 999;

预期输出(居然插进去了!):

1

MySQL 里外键默认生效,SQLite 里外键默认关闭——REFERENCES 只是写了句注释,不拦任何数据。必须每个连接先执行:

PRAGMA foreign_keys = ON;

再插同样的数据,就会被拒:

Runtime error: FOREIGN KEY constraint failed

口诀:SQLite 开库两件事——打开文件,打开外键。用 Python 连接时,connect 之后第一句就执行这条 PRAGMA。

先清掉刚才的幽灵数据:

DELETE FROM article WHERE user_id = 999;

7.3 级联删除:ON DELETE CASCADE

外键打开后,还能声明「删作者时他的文章跟着删」:

CREATE TABLE comment (
    id      INTEGER PRIMARY KEY,
    text    TEXT NOT NULL,
    user_id INTEGER NOT NULL REFERENCES user(id) ON DELETE CASCADE
);

这样删除一个 user,该用户的 comment 会被数据库自动清掉,不留孤儿数据。注意:建表时就得声明,事后改不了(SQLite 的 ALTER 能力很弱,改表结构通常是「建新表 → 搬数据 → 换名」)。

7.4 动手改

  1. 打开外键后,给 comment 插一条 user_id = 888 的评论,看报错
  2. 建带 ON DELETE CASCADE 的 comment 表,删掉一个用户,验证他的评论也没了
  3. 用 LEFT JOIN 查「没有发表过任何文章的用户」

7.5 小结

  • JOIN 连表查询与 MySQL 写法相同,别名 + ON 条件
  • SQLite 外键默认关闭,每个连接都要 PRAGMA foreign_keys = ON
  • 级联规则建表时声明;SQLite 改表结构靠「建新表换名」

下一章:综合练习:用 Python 操作 SQLite 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。