当前位置:首页 > 技术知识 > 正文内容

第 11 章:表连接 (JOIN) - PostgreSQL入门

maynowei2周前 (08-07)技术知识10

欢迎来到关系型数据库的“灵魂”所在!

到目前为止,我们所有的操作都只围绕着一张 friends 表。但在真实的世界里,数据总是被分散在不同的表里,并通过某种“关系”联系在一起。


比如,一个博客系统,会有“用户表”和“文章表”。文章表里只会记录作者的 ID,而不会把作者的姓名、邮箱等信息再存一遍。当我们想查询“某篇文章的标题以及作者的姓名”时,就需要把这两张表连接起来。

JOIN 就是实现这一魔法的咒语。它能根据两张或多张表之间的共同字段,将它们像拼图一样组合在一起,形成一个临时的、更宽的表,让我们可以在上面进行查询。


11.1 理解关系:一对一、一对多、多对多

在连接表之前,我们得先建立一些新的表来模拟真实场景。

场景设定:我们来为一个简单的博客系统设计数据表。

第一步:创建 users
这张表用来存放我们的用户。

CREATE TABLE users (
    user_id INT PRIMARY KEY, -- 使用主键约束,保证ID唯一且非空
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100)
);
  • PRIMARY KEY (主键): 这是表中最重要的约束,它保证 user_id 这一列的值是唯一非空的,是每一行记录的唯一身份证。

第二步:创建 posts
这张表用来存放文章。

CREATE TABLE posts (
    post_id INT PRIMARY KEY,
    author_id INT, -- 这个将用来关联 users 表
    title VARCHAR(200),
    content TEXT,
    FOREIGN KEY (author_id) REFERENCES users(user_id) -- 定义外键
);
  • FOREIGN KEY (author_id) REFERENCES users(user_id): 这是外键约束。它建立了两张表之间的“关系”。它告诉数据库:posts 表的 author_id 这一列,必须引用 users 表中某个已经存在的 user_id。这保证了你不可能创建一篇“不存在的幽灵作者”的文章,维护了数据的引用完整性

这就是一个典型的 一对多 (One-to-Many) 关系:一个 user 可以写多篇 post,但一篇 post 只能有一个 user 作者。

第三步:插入一些数据

-- 插入用户
INSERT INTO users (user_id, username, email) VALUES
(1, '老王', 'wang@example.com'),
(2, '李雷', 'li@example.com'),
(3, '韩梅梅', 'han@example.com');

-- 插入文章
INSERT INTO posts (post_id, author_id, title, content) VALUES
(101, 1, 'PostgreSQL入门', '内容...'),
(102, 2, 'JOIN的艺术', '内容...'),
(103, 1, '深入理解索引', '内容...'),
(104, 4, '一篇不存在作者的文章'); -- 这句会失败!因为users表里没有ID为4的用户。

请注意,最后一条 INSERT 会因为外键约束而失败,这是我们期望看到的!


12.2INNER JOIN(内连接)

INNER JOIN 是最常用、最直观的连接方式。它会返回两张表中连接字段能够匹配上的所有行。

可以把它想象成取两张表的“交集”。

问题:我们想查询所有文章的标题,以及其作者的用户名。

SELECT
    p.title,
    u.username
FROM
    posts AS p
INNER JOIN
    users AS u ON p.author_id = u.user_id;

语法解析 :

  1. FROM posts AS p: 我们从 posts 表开始,并给它起了个别名 p
  2. INNER JOIN users AS u: 我们要将它与 users 表(别名 u)进行内连接。
  3. ON p.author_id = u.user_id: 这是连接的核心! ON 关键字后面跟着连接条件。这里是“当 posts 表的 author_id 等于 users 表的 user_id 时,就把这两行拼在一起”。

执行结果:

      title       | username
------------------+----------
 PostgreSQL入门   | 老王
 JOIN的艺术       | 李雷
 深入理解索引     | 老王
(3 rows)

看!我们成功地把两张表的信息“缝合”在了一起!


11.3LEFT JOIN(左连接)

现在,有个新问题:如果我们想列出所有的用户,以及他们分别发表了哪些文章呢?如果某个用户没发表过文章,我们希望他仍然出现在列表里。

INNER JOIN 做不到这一点,因为它只返回能匹配上的。这时,LEFT JOIN 就派上用场了。

LEFT JOIN 会返回左表 (FROM 后面的表) 的所有行,以及右表中能匹配上的行。如果右表中没有匹配的行,那么从右表选择的列将显示为 NULL

问题:列出所有用户,以及他们写的文章标题。

SELECT
    u.username,
    p.title
FROM
    users AS u
LEFT JOIN
    posts AS p ON u.user_id = p.author_id;

执行结果:

 username |      title
----------+------------------
 老王     | PostgreSQL入门
 老王     | 深入理解索引
 李雷     | JOIN的艺术
 韩梅梅   | NULL  -- 韩梅梅没有写过文章,但她仍然出现在结果里!
(4 rows)

LEFT JOIN 在“以一张主表为基准,去关联补充信息”的场景下非常有用。


11.4RIGHT JOIN(右连接)

RIGHT JOINLEFT JOIN 正好相反。它会返回右表 (JOIN 后面的表) 的所有行。如果左表中没有匹配的行,那么从左表选择的列将显示为 NULL

实际上,A RIGHT JOIN B 完全等价于 B LEFT JOIN A。所以,RIGHT JOIN 并不常用,因为我们总是可以通过调整表的顺序,用 LEFT JOIN 来实现同样的目的,这样更容易理解。


11.5FULL OUTER JOIN(全外连接)

这个更大胆,它会返回左表和右表中所有的行

  • 如果某行在另一张表中能找到匹配,就合并。
  • 如果左表的某行在右表没匹配,右表的列就为 NULL
  • 如果右表的某行在左表没匹配,左表的列就为 NULL

可以把它想象成取两张表的“并集”。


11.6CROSS JOIN(交叉连接) 和自连接

  • CROSS JOIN: 笛卡尔积。它会返回左表的每一行与右表的每一行的所有可能组合。结果行数 = 左表行数 × 右表行数。它不需要 ON 条件。这在生成测试数据或某些特定组合分析时有用,但日常查询中要小心使用,因为它可能产生巨大的结果集。
  • 自连接 (Self Join): 这不是一种新的 JOIN 类型,而是一种技巧:一张表自己和自己进行连接
    • 场景:假设 users 表还有一个 manager_id 列,指向另一个 user_id,代表他的经理。我们想查询每个员工和他经理的名字。
    • 做法FROM users AS employees JOIN users AS managers ON employees.manager_id = managers.user_id。这里,我们把 users 表想象成了两张独立的表:“员工表”和“经理表”。

本章小结

你已经征服了 SQL 中最强大、最核心的概念之一!

  • 我们理解了主键外键是如何构建起表与表之间的“关系”的。
  • 掌握了最常用的 INNER JOIN,用于获取两张表的“交集”。
  • 掌握了非常有用的 LEFT JOIN,用于“以左表为准,补充右表信息”。
  • 了解了 RIGHT JOINFULL OUTER JOIN 的概念。

JOIN 的能力是构建复杂数据查询的基石。从现在开始,你的查询将不再局限于单张表,而是可以在一个由多张表构成的关系网络中自由穿梭。

在下一章,我们将学习 子查询 (Subquery),这是另一种组合和嵌套查询的方式,它能让我们写出结构更复杂的 SQL。准备好挑战更深层次的查询了吗?我们下一章见!

相关文章

单打独斗的产品设计师工作流程总结

来人人都是产品经理【起点学院】,BAT实战派产品总监手把手系统带你学产品、学运营。我从入行开始就在一个做自己产品的小公司工作,到现在已经三年了。刚开始工作的时候什么也不懂,老板说让出效果图,就开始直接...

去哪儿暑期PM实习一月记:在互联网公司做产品实习是怎样一种体验

人人都是产品经理旗下【起点学院】推出产品经理“365天”成长计划,BAT大牛带你学产品! 在毕业前的最后一个暑假,缘分使然找了几个月暑期实习之后进入了去哪儿,申请提前入职工作至今正好满一个月。原先有在...

苹果编程Objective C与Swift谁更牛?

小鹏大学刚刚毕业,软件开发方面的东西学的不是很多,听好多同学说做iOS开发工资上万是很容易的,踌躇满志,一直想自学iOS开发,可突如其来的一件事让他瞬间迷茫了。时间:2014年9月10日10点地点:某...

机器人需求驱动导航新SOTA,成功率提升15%!浙大&vivo联手打造

CogDDN团队 投稿量子位|公众号QbitAI让机器人像人一样边看边理解,来自浙江大学和vivo人工智能实验室的研究团队带来了新进展。正如视频所展示的,机器人在复杂的室内环境中不仅能自主探索,还具备...

微软明年要停止SQL Server 2005的技术支持了

站长之家(Chinaz.com)12月28日消息据外媒消息称,微软将于明年停止为SQL Server 2005提供技术支持,即不再为其提供新的安全补丁、新功能、应用升级等服务。且表示在停止技术支持后,...

ExpandListView 的一种巧妙写法(三十的另一种写法)

ExpandListView大家估计也用的不少了,一般有需要展开的需求的时候,大家不约而同的都想到了它然后以前自己留过记录的一般都会找找以前自己的代码,没有记录习惯的就会百度、谷歌,这里吐槽一下,好几...