首页 存档 技术 查看内容

SQL 经典回顾:JOIN 表连接操作不完全指南

2018-3-30 13:00 |来自: 互联网 446 0

摘要: 来自:码农网 链接:www.codeceo.com/article/sql-join-guide.html(点击尾部阅读原文前往) 英文原文:https://blog.jooq.org/2017/01/12/a-probably-incomplete-comprehensive-guide-to-the-many-different-ways-t ...

来自:码农网

链接:www.codeceo.com/article/sql-join-guide.html(点击尾部阅读原文前往)

英文原文:https://blog.jooq.org/2017/01/12/a-probably-incomplete-comprehensive-guide-to-the-many-different-ways-to-join-tables-in-sql/

翻译作者:码农网 小峰


也许最强大的SQL功能是JOIN操作。这让所有非关系数据库羡慕不已,因为当你想“合并”两个数据集时,这个概念是如此简单,并且又普遍适用。

简单地说,连接两个表,就是将一个表中的每一行与另一个表中的每一行结合起来。来自SQL Masterclass的插图展示了这个原理。

参见我们最近关于使用Venn图来说明JOIN的文章。上面的插图比较了INNER JOIN和不同的OUTER JOIN操作,但是这些并不是所有的可能性。让我们从更系统的角度来看问题。

请注意,每当本文中我说“X发生在Y之前”时,我的意思是“逻辑上,X发生在Y之前”。数据库优化器仍然可以选择在X之前执行Y,因为这更快,而不改变结果。有关操作的语法/逻辑顺序的更多信息点击这里查看。

好的,让我们一个个查看所有的join类型吧!

CROSS JOIN(交叉连接)

最基本的JOIN操作是真正的笛卡尔乘积。它只是组合一个表中的每一行和另一个表中的每一行。维基百科通过一副卡片给出了笛卡尔乘积的最佳例子,交叉连接ranks表和suits表:

在现实世界的场景中,CROSS JOIN在执行报告时非常有用,例如,你可以生成一组日期(例如一个月的天数)并与数据库中的所有部门交叉连接,以创建完整的天/部门表。使用PostgreSQL语法:

想象一下,我们有以下数据:

现在结果将如下所示:

 -------- ------------ 
| day | department | -------- ------------ | Jan 01 | Dept 1 |
| Jan 01 |
Dept 2 | | Jan 01 | Dept 3 |
| Jan 02 |
Dept 1 | | Jan 02 | Dept 2 |
| Jan 02 |
Dept 3 | | ... | ... |
| Jan 31 |
Dept 1 | | Jan 31 | Dept 2 |
| Jan 31 |
Dept 3 | -------- ------------

现在,在每个天/部门组合中,你可以计算该部门的每日收入,或其他。

特点

CROSS JOIN是笛卡尔乘积,即“乘法”中的乘积。数学符号使用乘号表示此操作:A×B,或在本文例子中:days×departments。

与“普通”算术乘法一样,如果两个表中有一个为空(大小为零),则结果也将为空(大小为零)。这是完全有道理的。如果我们将前面的31天与0个部门组合,我们将获得0天/部门组合。同样的,如果我们将空日期范围与任何数量的部门组合,我们也会获得0天/部门组合。

换一种说法:

size(result) = size(days) * size(departments)

替代语法

以前,在ANSI JOIN语法被引入到SQL之前,大家就会在FROM子句中写以逗号分隔的表格列表来编写CROSS JOIN。上面的查询等价于:

SELECT *FROM
  generate_series(    
'2017-01-01'::TIMESTAMP,
'2017-01-01'::TIMESTAMP INTERVAL '1 month -1 day',
INTERVAL '1 day' ) AS days(day), departments

一般来说,我强烈建议使用CROSS JOIN关键字,而不是以逗号分隔的表格列表,因为如果你有意地想要执行CROSS JOIN,那么没有什么可以比使用实际的关键字能更好地传达这个意图(对下一个开发人员而言)。何况用逗号分隔的表格列表中有这么多地方都有可能会出错。你肯定不希望看到这样的事情!

INNER JOIN(Theta-JOIN)

构建在先前的CROSS JOIN操作之上,INNER JOIN(或者只是简单的JOIN,有时也称为“THETA”JOIN)允许通过某些谓词过滤笛卡尔乘积的结果。大多数时候,我们把这个谓词放在ON子句中,它可能是这样的:

SELECT *
-- Same as before
FROM generate_series(
'2017-01-01'::TIMESTAMP,
'2017-01-01'::TIMESTAMP INTERVAL '1 month -1 day',
INTERVAL '1 day'
) AS days(day)
-- Now, exclude all days/departments combinations for
-- days before the department was created
JOIN departments AS d ON day
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部