你需要的每一个 SQL 连接
好吧……也许不是每次连接都用。但这张速查表帮助我在数据库 101 期中考试中获得了 104% 的成绩,所以它一定很有价值。
注意:很多标记我无法在 dev.to 上进行。所以,虽然我允许这篇文章完整地交叉发布,但如果没有“请注意!”的背景高亮、文本内的交叉链接、目录等,我在文中提到的很多内容就变得毫无意义了。
我建议在我的原始博客上阅读它,而不是在 dev.to 上,然后再回到 dev.to 进行讨论!
我费了好大劲才找到我以前的学校笔记,因为我当时甚至都没在标题里加“连接”这个词。我把笔记命名为“SQL 中的集合运算”。这才是真正的重点,因为无论你用 SQL、Excel VLOOKUP、Python,还是用纸笔来比较一个记录列表和另一个记录列表,都无关紧要。把一个“集合”和另一个“集合”结合起来,作为一个商业问题,就是数学。更棒的是,这是有趣的数学,而不是难懂的数学!这就是维恩图——那种让你像小学学生一样随心所欲涂鸦的数学。
SQL 代码有助于了解您的业务问题需要合并的两组记录(每条“记录”代表现实世界中的某个实体,例如一个人、一张发票或一个国家/地区)是否位于同一个关系数据库管理系统 (RDBMS)中,通常简称为“数据库”。所有此类系统都具备使用 SQL 编程语言提取数据的功能。
-
如果您是Python数据分析师,请务必学习一些 SQL,以便您可以利用其功能对数据所在的数据库进行处理。
-
如果您是Salesforce分析师或系统管理员,您可能遇到过报表和 SOQL 的限制。也许您通过将两个表导出到 Excel,然后执行
VLOOKUP
操作来连接它们来解决这些问题。为了更上一层楼,您可能想探索 Python,而不是 SQL——除非您的 IT 部门已经将 Salesforce 组织的数据备份到传统数据库。那么您需要了解有关 SQL 的所有信息,因为它将为您节省大量时间!
我经常使用 Oracle 数据库,因此我发现 Oracle 风格的 SQL 代码输入速度最快,因此我将以此为例进行说明。您可以注册一个免费账户并试用他们的Live SQL工具,在线运行 Oracle SQL 代码。
要将其转化为另一种“风格”的 SQL,你可能需要用 Google 搜索我使用的关键词,并结合你的数据库名称。例如,当我的full outer join
命令在 MySQL 数据库中无法使用时,我谷歌搜索了“'full outer join' mysql”,结果发现 MySQL 风格的 SQL 并不包含任何full outer join
命令。相反,你必须巧妙地组合一些较小的集合运算 (这就像在维恩图中,一次仔细地涂满整个圆圈,而不是用蜡笔一次涂满整个图)。
专业提示:收藏本文并将其作为参考指南。
无论您对 SQL 了解多少,都可以使用本文顶部的目录一次阅读一个部分。
- 本指南虽然简单,但篇幅较长,所以如果你正在学习,建议每天阅读一种“加入类型”。(除非你要坐长途巴士!)
- 如果您了解基本知识并且只需要比较命令,请直接跳到您感兴趣的命令。
我们的样本数据
表“ A
”内容(CONVENTION
)
CONVENTION
是参加会议的人员及其工作地点的列表。
(是的,这是一个非常八卦的活动,要求参加者提供社会安全号码。)
社会安全号码 | 名称_lf | 酸碱度 | em | 公司 |
---|---|---|---|---|
A1A1A1 | 阿姆吉特·阿努什 | 1111111 | 111@example.com | 苹果 |
B2B2B | 博尔赫斯,贝尼塔 | 2222222 | 222@example.com | 布瓦龙 |
C3C3C3 | 凯茜·库姆斯 | 3333333 | 333@example.com | CVS |
D4D4D4 | 达赫尔,达尔维什 | 4444444 | 444@example.com | 戴尔 |
E5E5E5 | 埃利斯,埃兹拉 | 5555555 | 555@example.com | 法国电力公司 |
F6F6F6 | 弗朗西斯·富尔维娅 | 6666666 | 666@example.com | 凡士通 |
表“ B
”内容(RESTAURANT
)
RESTAURANT
是餐厅常客的列表,包括他们最喜欢的食物以及他们的年龄。
(是的,这是一家非常爱管闲事的餐厅,会向常客询问社会安全号码。)
- 请注意 Cathy Combs 的电子邮件地址是“ccc”,而不是“333”。
- 请注意 Frances Fulvia 的社会保障号码中的拼写错误。
社会的 | 名称_fl | 电话 | 电子邮件 | 最喜欢的食物 | 年龄 |
---|---|---|---|---|---|
C3C3C3 | 凯茜·库姆斯 | 3333333 | ccc@example.com | 胡萝卜 | 33 |
D4D4D4 | 达维什·达赫尔 | 4444444 | 444@example.com | 多力多滋 | 四十四 |
E5E5E5 | 埃兹拉·埃利斯 | 5555555 | 555@example.com | 菊苣 | 55 |
FFF666 | 弗朗西丝·富尔维亚 | 6666666 | 666@example.com | 薯条 | 66 |
G7G7G7 | 高 | 7777777 | 777@example.com | 蒜 | 77 |
H8H8H8 | 海伦·霍珀 | 8888888 | 888@example.com | 鹰嘴豆泥 | 88 |
创建此数据的代码(“DDL”和“DML”)
如果您想亲自尝试,这里有在 Oracle 数据库中创建表并使用我们的示例数据填充它们的代码CONVENTION
。RESTAURANT
drop table CONVENTION;
create table CONVENTION (
ssn varchar2(6) not null
, name_lf varchar2(30) not null
, ph varchar2(7) not null
, em varchar(15) not null
, company varchar(15) not null
);
insert into CONVENTION values ('A1A1A1', 'Amjit, Anush', '1111111', '111@example.com', 'Apple');
insert into CONVENTION values ('B2B2B2', 'Borges, Benita', '2222222', '222@example.com', 'Boiron');
insert into CONVENTION values ('C3C3C3', 'Combs, Cathy', '3333333', '333@example.com', 'CVS');
insert into CONVENTION values ('D4D4D4', 'Daher, Darweesh', '4444444', '444@example.com', 'Dell');
insert into CONVENTION values ('E5E5E5', 'Ellis, Ezra', '5555555', '555@example.com', 'EDF');
insert into CONVENTION values ('F6F6F6', 'Fulvia, Frances', '6666666', '666@example.com', 'Firestone');
drop table RESTAURANT;
create table RESTAURANT (
social varchar2(6) not null
, name_fl varchar2(30) not null
, phone varchar2(7) not null
, email varchar2(15) not null
, fav_food varchar2(10) not null
, age int not null
);
insert into RESTAURANT values ('C3C3C3', 'Cathy Combs', '3333333', 'ccc@example.com', 'Carrots', 33);
insert into RESTAURANT values ('D4D4D4', 'Darweesh Daher', '4444444', '444@example.com', 'Doritos', 44);
insert into RESTAURANT values ('E5E5E5', 'Ezra Ellis', '5555555', '555@example.com', 'Endives', 55);
insert into RESTAURANT values ('FFF666', 'Frances Fulvia', '6666666', '666@example.com', 'Fries', 66);
insert into RESTAURANT values ('G7G7G7', 'Grace Gao', '7777777', '777@example.com', 'Garlic', 77);
insert into RESTAURANT values ('H8H8H8', 'Helen Hopper', '8888888', '888@example.com', 'Hummus', 88);
谁重叠以及如何重叠
假设我们是一家大公司。规模如此之大,我们既经营会议,又拥有餐厅。我们想找出两家客户名单之间的“重叠部分”,并进行相应的分析。
实际上,关于我为什么选择这些查询和输出,我只想说这些。它们根本没有任何商业意义。我选择它们是为了演示不同风格的 SQL 查询能做什么和不能做什么!
但回到组合我们的集合的事情上:
一如既往,在比较来自两个不同数据集的“人员”记录时,必须确定什么才能“证明”两条记录代表同一个“现实世界的人”。姓名匹配吗?邮箱匹配吗?社会保障号匹配吗(记住,这些信息在人们去世后会被重复使用)?还是以上几种信息的组合?
对于我们的例子,我们将研究两种不同的数据组合方式,只是为了展示我们的代码能力。
在阅读代码之前,请务必查看CONVENTION
并RESTAURANT
注意:
- 当我们加入时
A.ssn=B.social
,Cathy-Ezra (3-5) 比赛- Anush、Benita 和“Frances w/
ssn
F6F6F6”仍然是CONVENTION
- “Frances w/
ssn
FFF666”,Grace 和 Helen 仍然是独一无二的RESTAURANT
- Anush、Benita 和“Frances w/
- 当我们加入时
A.ph=B.phone and A.em=B.email
,Darweesh-Frances (4-6) 比赛
您已完全了解情况!让我们来看看 5 种“加入类型”中的第一个。
加入类型:“In A
”
对于这种连接类型,我们预计有 6 行输出(Anush-Frances——来自的所有人CONVENTION
)。
如果这些人中的任何一个“也存在”于RESTAURANT
(根据我们选择的“匹配标准”的定义),我们希望从中看到关于他们的详细信息RESTAURANT
。
LEFT OUTER JOIN
SQL 查询,left outer join
示例 1/4
首先,我们将根据社会保障号码进行匹配,因此 Cathy 有“表 B”中的详细信息,但 Frances 没有。
select A.name_lf, A.company, B.name_fl, B.fav_food
from CONVENTION A
left outer join RESTAURANT B on A.ssn = B.social;
查询输出,left outer join
示例 1/4
名称_lf | 公司 | 名称_fl | 最喜欢的食物 |
---|---|---|---|
阿姆吉特·阿努什 | 苹果 | ||
博尔赫斯,贝尼塔 | 布瓦龙 | ||
凯茜·库姆斯 | CVS | 凯茜·库姆斯 | 胡萝卜 |
达赫尔,达尔维什 | 戴尔 | 达维什·达赫尔 | 多力多滋 |
埃利斯,埃兹拉 | 法国电力公司 | 埃兹拉·埃利斯 | 菊苣 |
弗朗西斯·富尔维娅 | 凡士通 |
SQL 查询,left outer join
示例 2/4
接下来,我们将通过电话和电子邮件进行匹配,因此 Frances 有“表 B”的详细信息,但 Cathy 没有。)
select A.name_lf, A.company, B.name_fl, B.fav_food
from CONVENTION A
left outer join RESTAURANT B on A.ph = B.phone and A.em = B.email;
查询输出,left outer join
示例 2/4
名称_lf | 公司 | 名称_fl | 最喜欢的食物 |
---|---|---|---|
阿姆吉特·阿努什 | 苹果 | ||
博尔赫斯,贝尼塔 | 布瓦龙 | ||
凯茜·库姆斯 | CVS | ||
达赫尔,达尔维什 | 戴尔 | 达维什·达赫尔 | 多力多滋 |
埃利斯,埃兹拉 | 法国电力公司 | 埃兹拉·埃利斯 | 菊苣 |
弗朗西斯·富尔维娅 | 凡士通 | 弗朗西丝·富尔维亚 | 薯条 |
SQL 查询,left outer join
示例 3/4
接下来,我们将尝试(错误地)抑制50 岁以下任何人的详细信息name_fl
。fav_food
select A.name_lf, A.company, B.name_fl, B.fav_food
from CONVENTION A
left outer join RESTAURANT B on A.ssn = B.social
where B.age >= 50;
查询输出,left outer join
示例 3/4
名称_lf | 公司 | 名称_fl | 最喜欢的食物 |
---|---|---|---|
埃利斯,埃兹拉 | 法国电力公司 | 埃兹拉·埃利斯 | 菊苣 |
笔记
尽管B
在我们的连接中“来自”的行是可选的,但在添加过滤器时B
,我们实际上将这个“左连接”变成了“内连接”,其中我们的数据必须出现在两个表中。
我们实际上所做的是过滤掉没有年龄(因为他们不在表中B
)或年龄小于 50 的人的全部记录。
这是一个常见错误。我们将在下一个示例中修复它。
在数学中,当你将数字相减时,相减的顺序很重要。
同样,在使用 SQL 解决业务问题时,考虑“连接”和“过滤”数据的顺序也很重要。
SQL 查询,left outer join
示例 4/4
现在我们实际上将抑制50 岁或以下任何人的name_fl
详细fav_food
信息。
select A.name_lf, A.company, B.name_fl, B.fav_food
from CONVENTION A
left outer join (select * from RESTAURANT where age >= 50) B on A.ssn = B.social;
查询输出,left outer join
示例 4/4
名称_lf | 公司 | 名称_fl | 最喜欢的食物 |
---|---|---|---|
阿姆吉特·阿努什 | 苹果 | ||
博尔赫斯,贝尼塔 | 布瓦龙 | ||
凯茜·库姆斯 | CVS | ||
达赫尔,达尔维什 | 戴尔 | ||
埃利斯,埃兹拉 | 法国电力公司 | 埃兹拉·埃利斯 | 菊苣 |
弗朗西斯·富尔维娅 | 凡士通 |
笔记
在我们更正后的查询中,我们在将其视为之前按年龄进行了预过滤 ,这解决了上一个示例中的问题。RESTAURANT
B
这是第一个“连接类型”。我们来看看第二个。
连接类型:“在A
但不在B
”
对于这种连接类型,我们期望有 3 行输出(Anush+Benita+Cathy 或 Anush+Benita+Frances,取决于我们选择的“匹配标准”)。
根据定义,表格B
不是您的业务问题的最终输出的一部分,因此请记住,以下所有方法都只包含表格中的“详细信息” A
。
NOT IN
SQL 查询,not in
示例 1/3
not in
当你只匹配一列时就很好了。
select A.name_lf, A.company
from CONVENTION A
where A.ssn not in ( select B.social from RESTAURANT B );
查询输出,not in
示例 1/3
名称_lf | 公司 |
---|---|
阿姆吉特·阿努什 | 苹果 |
博尔赫斯,贝尼塔 | 布瓦龙 |
弗朗西斯·富尔维娅 | 凡士通 |
SQL 查询,not in
示例 2/3
not in
当您需要匹配多个列时,就会变得危险——您必须将多个列连接成一个列,并负责任地处理空白/空值。
对于多列匹配,这不是推荐的做法NOT EXISTS
。请使用。
此查询仅供展示!
select A.name_lf, A.company
from CONVENTION A
where nvl(A.ph,'')||'~'||nvl(A.em,'') not in ( select nvl(B.phone,'')||'~'||nvl(B.email,'') from RESTAURANT B );
查询输出,not in
示例 2/3
名称_lf | 公司 |
---|---|
阿姆吉特·阿努什 | 苹果 |
博尔赫斯,贝尼塔 | 布瓦龙 |
凯茜·库姆斯 | CVS |
SQL 查询,not in
示例 3/3
我们的第三个not in
示例甚至不是表之间的真正连接:请注意,它RESTAURANT
甚至不在查询中。
我只是想指出,这种输入方式与not in
您在向查询添加手动输入值过滤器时使用的方式相同。
select A.name_lf, A.company
from CONVENTION A
where A.ssn not in ( 'B2B2B2','XYZZY','E5E5E5' );
查询输出,not in
示例 3/3
名称_lf | 公司 |
---|---|
阿姆吉特·阿努什 | 苹果 |
凯茜·库姆斯 | CVS |
达赫尔,达尔维什 | 戴尔 |
弗朗西斯·富尔维娅 | 凡士通 |
<> ALL
这和完全一样not in
,只是你输入的<> all
是 。本节中的每个例子都not in
可以用 来写<> all
。
SQL查询
select A.name_lf, A.company
from CONVENTION A
where A.ssn <> all ( select B.social from RESTAURANT B );
查询输出
名称_lf | 公司 |
---|---|
阿姆吉特·阿努什 | 苹果 |
博尔赫斯,贝尼塔 | 布瓦龙 |
弗朗西斯·富尔维娅 | 凡士通 |
MINUS
有了minus
,我们就不能输出不符合我们的“匹配标准”的列。
也就是说,如果我们的业务问题是“仅出现在 中的所有值A
”的简单“虚拟检查”列表,那么这种有限的输出可能就足够了。
SQL 查询,minus
示例 1/2
select A.ssn
from CONVENTION A
minus
select B.social
from RESTAURANT B;
查询输出,minus
示例 1/2
社会安全号码 |
---|
A1A1A1 |
B2B2B |
F6F6F6 |
SQL 查询,minus
示例 2/2
select A.ph, A.em
from CONVENTION A
minus
select B.phone, B.email
from RESTAURANT B;
查询输出,minus
示例 2/2
酸碱度 | em |
---|---|
1111111 | 111@example.com |
2222222 | 111@example.com |
3333333 | 111@example.com |
NOT EXISTS
如果您需要在复杂查询中使用多列“匹配条件”执行“in A
,但不”,请使用此功能!B
where not exists (...)
是编写涉及多列匹配的“匹配条件”的复杂查询最有用的语法。
这种方法支持“进一步的过滤” ——只需将它们作为负责“匹配”操作的子句之外的A
附加and
子句即可。or
where
如果其中有其余过滤器or
,请务必使用括号,以确保您不会意外地将其变为where not exists (...)
可选的。
SQL查询
SELECT A.name_lf, A.company
FROM CONVENTION A
WHERE NOT EXISTS (
SELECT NULL
FROM RESTAURANT B
WHERE A.ph = B.phone and A.em = B.email
);
查询输出
名称_lf | 公司 |
---|---|
阿姆吉特·阿努什 | 苹果 |
博尔赫斯,贝尼塔 | 布瓦龙 |
凯茜·库姆斯 | CVS |
LEFT OUTER JOIN ... B.... IS NULL
我实在想不出任何理由在实践中使用“LEFT OUTER JOIN
加号B.joinColumn IS NULL
”语法。它完全是过度使用。
但是...它在概念上与“A
要么同时存在B
,要么同时存在”的常见方法相关,因此这是一个有趣的脑力练习,以确保您理解。
NOT EXISTS
当您遇到没有语法的报告编写工具(例如Cognos Report Studio或Python+Pandas)时,熟悉它也是一种很好的“作弊”模式。
对于这种方法,对参与操作的所有列使用过滤器至关重要。IS NULL
B
LEFT OUTER JOIN
否则,如果您的数据集中包含很多NULL
值,您可能会得到意外的结果。
这种方法支持“进一步的过滤” ——只需将它们作为负责“匹配”操作的子句之外的A
附加and
子句即可。or
where
如果其中有其余过滤器or
,请务必使用括号,以确保您不会意外地将where ... is null
过滤器变为可选的。
SQL查询
select A.name_lf, A.company
from CONVENTION A
left outer join RESTAURANT B on A.ph = B.phone and A.em = B.email
where B.phone is null
and B.email is null;
查询输出
名称_lf | 公司 |
---|---|
阿姆吉特·阿努什 | 苹果 |
博尔赫斯,贝尼塔 | 布瓦龙 |
凯茜·库姆斯 | CVS |
恭喜您完成了第二个“加入类型”。接下来是第三个!
连接类型:“在A
、B
或两者中”
对于这种连接类型,我们期望输出 9 行(Anush-Helen,Cathy 或 Frances 加倍,取决于我们选择的“匹配标准”)。
UNION
SQL 查询,union
示例 1/2
select A.ssn
from CONVENTION A
union
select B.social
from RESTAURANT B;
查询输出,union
示例 1/2
社会安全号码 |
---|
A1A1A1 |
B2B2B |
C3C3C3 |
D4D4D4 |
E5E5E5 |
F6F6F6 |
FFF666 |
G7G7G7 |
H8H8H8 |
- 您看到重复的“Frances”数据了吗?
笔记
与一样minus
,我们不能输出不在我们的“匹配标准”中的列。
如果我们的业务问题是“来自任一表的所有可能值”的简单“虚拟检查”列表,则单列输出可能就足够了。
SQL 查询,union
示例 2/2
select A.ph, A.em
from CONVENTION A
union
select B.phone, B.email
from RESTAURANT B;
查询输出,union
示例 2/2
酸碱度 | em |
---|---|
1111111 | 111@example.com |
2222222 | 222@example.com |
3333333 | 333@example.com |
3333333 | ccc@example.com |
4444444 | 444@example.com |
5555555 | 555@example.com |
6666666 | 666@example.com |
7777777 | 777@example.com |
8888888 | 888@example.com |
- 您看到重复的“Cathy”数据了吗?
FULL OUTER JOIN
SQL 查询,full outer join
示例 1/2
select A.name_lf, A.company, B.name_fl, B.fav_food
from CONVENTION A
full outer join RESTAURANT B on A.ssn = B.social;
查询输出,full outer join
示例 1/2
名称_lf | 公司 | 名称_fl | 最喜欢的食物 |
---|---|---|---|
阿姆吉特·阿努什 | 苹果 | ||
博尔赫斯,贝尼塔 | 布瓦龙 | ||
凯茜·库姆斯 | CVS | 凯茜·库姆斯 | 胡萝卜 |
达赫尔,达尔维什 | 戴尔 | 达维什·达赫尔 | 多力多滋 |
埃利斯,埃兹拉 | 法国电力公司 | 埃兹拉·埃利斯 | 菊苣 |
弗朗西斯·富尔维娅 | 凡士通 | ||
弗朗西丝·富尔维亚 | 薯条 | ||
高 | 蒜 | ||
海伦·霍珀 | 鹰嘴豆泥 |
- 您看到重复的“Frances”数据了吗?
SQL 查询,full outer join
示例 2/2
select A.name_lf, A.company, B.name_fl, B.fav_food
from CONVENTION A
full outer join RESTAURANT B on A.ph = B.phone and A.em = B.email;
查询输出,full outer join
示例 2/2
名称_lf | 公司 | 名称_fl | 最喜欢的食物 |
---|---|---|---|
阿姆吉特·阿努什 | 苹果 | ||
博尔赫斯,贝尼塔 | 布瓦龙 | ||
凯茜·库姆斯 | CVS | ||
达赫尔,达尔维什 | 戴尔 | 达维什·达赫尔 | 多力多滋 |
埃利斯,埃兹拉 | 法国电力公司 | 埃兹拉·埃利斯 | 菊苣 |
弗朗西斯·富尔维娅 | 凡士通 | 弗朗西丝·富尔维亚 | 薯条 |
凯茜·库姆斯 | 胡萝卜 | ||
高 | 蒜 | ||
海伦·霍珀 | 鹰嘴豆泥 |
- 您看到重复的“Cathy”数据了吗?
MySQL 伪造FULL OUTER JOIN
这就是我之前提到的巧妙的技巧,用来弥补 MySQL 风格的 SQL 没有full outer join
命令这一事实。
SQL查询
select A.name_lf, A.company, B.name_fl, B.fav_food
from CONVENTION A
left outer join RESTAURANT B on A.ssn = B.social
union
select A.name_lf, A.company, B.name_fl, B.fav_food
from CONVENTION A
right outer join RESTAURANT B on A.ssn = B.social;
查询输出
名称_lf | 公司 | 名称_fl | 最喜欢的食物 |
---|---|---|---|
阿姆吉特·阿努什 | 苹果 | ||
博尔赫斯,贝尼塔 | 布瓦龙 | ||
凯茜·库姆斯 | CVS | 凯茜·库姆斯 | 胡萝卜 |
达赫尔,达尔维什 | 戴尔 | 达维什·达赫尔 | 多力多滋 |
埃利斯,埃兹拉 | 法国电力公司 | 埃兹拉·埃利斯 | 菊苣 |
弗朗西斯·富尔维娅 | 凡士通 | ||
弗朗西丝·富尔维亚 | 薯条 | ||
高 | 蒜 | ||
海伦·霍珀 | 鹰嘴豆泥 |
- 您看到重复的“Frances”数据了吗?
已经完成了一半了!继续阅读,了解第四种“连接类型”。
这个有很多选项,所以读起来会有点长。
连接类型:“A
同时B
”
对于这种连接类型,我们期望有 3 行输出(Cathy-Ezra 或 Darweesh-Frances,取决于我们选择的“匹配标准”)。
IN
SQL 查询,in
示例 1/3
select A.name_lf, A.company
from CONVENTION A
where A.ssn in ( select B.social from RESTAURANT B );
查询输出,in
示例 1/3
名称_lf | 公司 |
---|---|
凯茜·库姆斯 | CVS |
达赫尔,达尔维什 | 戴尔 |
埃利斯,埃兹拉 | 法国电力公司 |
笔记
in
非常适合:- 你只匹配一列,并且
- 你不需要查看或进一步过滤任何来自
B
SQL 查询,in
示例 2/3
select A.name_lf, A.company
from CONVENTION A
where nvl(A.ph,'')||'~'||nvl(A.em,'') in ( select nvl(B.phone,'')||'~'||nvl(B.email,'') from RESTAURANT B );
查询输出,in
示例 2/3
名称_lf | 公司 |
---|---|
达赫尔,达尔维什 | 戴尔 |
埃利斯,埃兹拉 | 法国电力公司 |
弗朗西斯·富尔维娅 | 凡士通 |
笔记
in
当你需要匹配多列时,情况会变得棘手——你必须将多列连接成一列,并妥善处理空值/空值。对于多列匹配,这不是推荐的做法exists
。请使用。这只是做个演示!
SQL 查询,in
示例 3/3
select A.name_lf, A.company
from CONVENTION A
where A.ssn in ( 'B2B2B2','XYZZY','E5E5E5' );
查询输出,in
示例 3/3
名称_lf | 公司 |
---|---|
博尔赫斯,贝尼塔 | 布瓦龙 |
埃利斯,埃兹拉 | 法国电力公司 |
笔记
- 这实际上并不是真正的表间连接:注意,这
RESTAURANT
甚至不在查询中。我只是想指出,这in
与在查询中添加手动值过滤器时使用的方法相同。
= ANY
SQL查询
select A.name_lf, A.company
from CONVENTION A
where A.ssn = any ( select B.social from RESTAURANT B );
查询输出
名称_lf | 公司 |
---|---|
凯茜·库姆斯 | CVS |
达赫尔,达尔维什 | 戴尔 |
埃利斯,埃兹拉 | 法国电力公司 |
笔记
这和 完全一样in
,只是你输入= any
的是 。 中的 3 个例子均in
适用。
INTERSECT
SQL 查询,intersect
示例 1/2
select A.ssn
from CONVENTION A
intersect
select B.social
from RESTAURANT B;
查询输出,intersect
示例 1/2
社会安全号码 |
---|
C3C3C3 |
D4D4D4 |
E5E5E5 |
笔记
与minus
和 一样union
,我们不能输出不在我们的“匹配条件”中的列。
如果我们的业务问题是“出现在两个表中的所有值”的简单“虚拟检查”列表,那么单列输出可能就足够了。
SQL 查询,intersect
示例 2/2
select A.ph, A.em
from CONVENTION A
intersect
select B.phone, B.email
from RESTAURANT B;
查询输出,intersect
示例 2/2
酸碱度 | em |
---|---|
4444444 | 444@example.com |
5555555 | 555@example.com |
6666666 | 666@example.com |
EXISTS
SQL查询
SELECT A.name_lf, A.company
FROM CONVENTION A
WHERE EXISTS (
SELECT NULL
FROM RESTAURANT B
WHERE A.ph = B.phone and A.em = B.email
);
查询输出
名称_lf | 公司 |
---|---|
达赫尔,达尔维什 | 戴尔 |
埃利斯,埃兹拉 | 法国电力公司 |
弗朗西斯·富尔维娅 | 凡士通 |
笔记
exists
in
比你的“匹配标准”涉及多列时更好。- 类似于
in
,exists
不允许您查看或进一步过滤来自 的详细信息B
。
INNER JOIN
SQL查询
select A.name_lf, A.company, B.name_fl, B.fav_food
from CONVENTION A
inner join RESTAURANT B on A.ph = B.phone and A.em = B.email;
查询输出
名称_lf | 公司 | 名称_fl | 最喜欢的食物 |
---|---|---|---|
达赫尔,达尔维什 | 戴尔 | 达维什·达赫尔 | 多力多滋 |
埃利斯,埃兹拉 | 法国电力公司 | 埃兹拉·埃利斯 | 菊苣 |
弗朗西斯·富尔维娅 | 凡士通 | 弗朗西丝·富尔维亚 | 薯条 |
=
{#equals}
连接表的简单=
方法非常普遍,并且通常在使用 SQL 连接表的教程中首先讲授。
它支持“进一步的过滤”——只需将它们作为负责“匹配”操作的子句之外的附加and
子句即可。or
where
如果其中有其余过滤器or
,请务必使用括号,以确保您不会意外地将“连接过滤器”变为可选项。
避免此类担忧是我稍微喜欢inner join
“ =
”方法的一个原因。
inner join
当我需要尝试确定要编写的查询时,我几乎总是使用显式命令。这有助于我在玩游戏时避免不小心犯下退格错误。
SQL查询
select A.name_lf, A.company, B.name_fl, B.fav_food
from CONVENTION A, RESTAURANT B
where A.ph = B.phone
and A.em = B.email;
查询输出
名称_lf | 公司 | 名称_fl | 最喜欢的食物 |
---|---|---|---|
达赫尔,达尔维什 | 戴尔 | 达维什·达赫尔 | 多力多滋 |
埃利斯,埃兹拉 | 法国电力公司 | 埃兹拉·埃利斯 | 菊苣 |
弗朗西斯·富尔维娅 | 凡士通 | 弗朗西丝·富尔维亚 | 薯条 |
近在咫尺,你就能尝到滋味了。还差一个——下面是第五种,也是最后一种“连接类型”。
连接类型:“A
要么连接B
,要么同时连接”
对于这种连接类型,我们期望有 6 行输出(Anush+Benita+Cathy1+Cathy2+Grace+Helen 或 Anush+Benita+Frances1+Frances2+Grace+Helen,取决于我们选择的“匹配标准”) 。
虽然没有专门用于此连接类型的 SQL 命令,但请仔细查看表示它的维恩图。您能看出“In A
,,, B
Or Both”连接中“中间被咬掉的部分”吗?您的任务是编写代码来去除“中间被咬掉的部分”。
(附注:要把这个维恩图做成一块不会在数据库 101 课程期末考试时破碎的糖饼干是非常困难的。用 SQL 制作它要容易得多!)
选择你自己的冒险
根据以下架构设计查询,将重叠圆圈的“中间部分切掉”:
- 使用您最喜欢的方法构建“在
A
、B
或两者中”查询,并将其视为您的新A
。 - 使用您最喜欢的方法构建“In Both
A
AndB
”查询,并将其视为您的新B
。 - 使用您最喜欢的“In But Not In ”方法将您的新内容
A
和新内容缝合在一起。B
A
B
FULL OUTER JOIN ... A.... IS NULL OR B.... IS NULL
使用这种方法时,对涉及操作的所有列和的所有列使用过滤器至关重要。IS NULL
A
B
FULL OUTER JOIN
否则,如果您的数据集中包含很多NULL
值,您可能会得到意外的结果。
当您执行此操作时,“ AND
”一起筛选来自同一个表的列,但“ OR
”一起筛选来自不同表的列,如下面的示例代码所示。
这种方法支持“进一步的过滤”——只需将它们作为负责“匹配”操作的子句之外的附加and
子句即可。or
where
确保将... or ...
负责“从中间咬一口”的整个过滤器括在其自己的括号中,以避免出现意外行为。
如果其余过滤器也包含or
在内,也请使用括号将它们括起来,以确保您不会意外地将“中间咬合”的过滤器变为可选项。
SQL查询
select A.name_lf, A.company, B.name_fl, B.fav_food
from CONVENTION A
full outer join RESTAURANT B on A.ph = B.phone and A.em = B.email
where
(
A.ph is null
and A.em is null
)
or
(
B.phone is null
and B.email is null
);
查询输出
名称_lf | 公司 | 名称_fl | 最喜欢的食物 |
---|---|---|---|
阿姆吉特·阿努什 | 苹果 | ||
博尔赫斯,贝尼塔 | 布瓦龙 | ||
凯茜·库姆斯 | CVS | ||
凯茜·库姆斯 | 胡萝卜 | ||
高 | 蒜 | ||
海伦·霍珀 | 鹰嘴豆泥 |
你成功了!感觉自己又聪明了多少?
更多资源
如果您喜欢这篇文章,您可能感兴趣的其他链接是:
- Mode Analytics 的SQL 教程
- Helen Anderson 撰写的《SQL JOIN 的全部内容》
- 如何从 Excel 过渡到 SQL(作者:Benn Stancil)
- Periscope Data 的SQL 中仅连接第一行的 4 种方法
- SQL 中 JOIN 的更多危险之处,作者:Alex Petralia
- Sadavath Sharma 撰写的SQL、Python 和 R 中的 JOIN
- David Wallace 撰写的《Python 和 SQL 重叠》