首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在3个表上使用外连接。

如何在3个表上使用外连接。
EN

Stack Overflow用户
提问于 2017-03-13 23:52:07
回答 3查看 66关注 0票数 0

在我的数据库中,我必须列出在瓜达尔卡纳尔岛战役中战斗过的所有船只的名称、排水量和火炮数量。为此,我需要使用3个表。名称来自舰船表,枪炮数量和排水量来自Classes表,战斗来自battles表。

代码语言:javascript
运行
复制
Create Table Classes (
    class Varchar(40),
    type Char (2),
    country Varchar(15),
    numGuns Int,
    bore Int,
    displacement Int
);
Create Table Ships (
    name Varchar(40),
    class Varchar(40),
    launched Int
);
Create Table Battles(
    name Varchar(40),
    date_fought Date
);

下面是我尝试使用的一个查询:

代码语言:javascript
运行
复制
Select Ships.name, displacement, numGuns
From (Classes Full Outer Join Ships ON Classes.class = Ships.class), Battles
Where Battles.name = 'Guadalcanal';

现在,这不起作用,主要是因为我认为我没有正确地使用外部连接。问题是我不知道如何对3个表使用外部连接。

EN

回答 3

Stack Overflow用户

发布于 2017-03-14 00:02:00

首先,确定您的主要信息来源在哪里。在这里,您正在寻找一场战斗以及相关的舰船及其类别。外部联接意味着它将返回一端,即使另一端没有匹配项也是如此。在这种情况下,如果你从战斗开始,你只需要匹配的船,所以:

代码语言:javascript
运行
复制
select     b.name 
from       Battles b 
inner join Ships   s on b.name = s.battle_name

我不认为你有任何东西可以把船和战斗联系起来。我的猜测是,您缺少一个将舰船与战斗相匹配的XREF表。

Battle_Ships

代码语言:javascript
运行
复制
+++++++++++++++
battle  | ship
+++++++++++++++
battle1 | ship1
battle1 | ship2
battle1 | ship3
battle2 | ship3
battle2 | ship4

有了这个,你就可以像这样得到战斗和船:

代码语言:javascript
运行
复制
select          b.name, s.name 
from            Battles      b 
left outer join Battle_Ships bs on b.name = bs.battle 
left outer join Ships        s  on bs.ship = s.name

然后你会想要得到船的类,所以你可以得到位移,但我猜这可能不存在,所以你会想要外连接它

代码语言:javascript
运行
复制
select          s.name, c.numGuns, c.displacement 
from            Ships   s 
left outer join Classes c on s.class = c.class

总而言之,你会得到类似这样的东西:

代码语言:javascript
运行
复制
select          b.name, s.name, c.numGuns, c.displacement 
from            Battles      b 
left outer join Battle_Ships bs on b.name = bs.battle 
left outer join Ships        s  on bs.ship = s.name 
left outer join Classes      c  on s.class = c.class 
where           b.name = 'Guadalcanal'

同样,left outer join意味着匹配左侧,如果存在则返回右侧。在这里,我们从战斗开始,然后匹配Battle_Ships (如果有),匹配船只(如果有),然后匹配类。您几乎不想使用完整的外部连接,除非您还想显示哪些船从未在战斗中(因为这样会允许左侧也是空的)。

票数 2
EN

Stack Overflow用户

发布于 2017-03-14 00:01:18

战斗和职业/舰船共享的密钥是什么?一旦你有了它,下面的方法就应该起作用了。此编辑假设船舶是与Battle共享的关键。

代码语言:javascript
运行
复制
SELECT Ships.name, displacement, numGuns
FROM Ships 
FULL JOIN Classes ON Classes.class = Ships.class,
FULL JOIN Battles ON Battles.ThatKey = Ships.SameKey
WHERE Battles.name = 'Guadalcanal';
票数 0
EN

Stack Overflow用户

发布于 2017-03-14 07:57:04

首先,您希望每个表中都有一个主键,以便您可以准确地将这些表彼此关联起来。如果class在classes表中是唯一的,并且每个Ship记录都有一个Classes表中列出的类,那么它将作为Classes表中的一个键。除非每个ship名称都是唯一的,否则您还需要在该表中有一个主键。主键在战斗中也是需要的。战斗表和舰船表之间很可能存在多对多的关系。一艘船可以处于多个战斗中,一场战斗可以有多艘船。需要另一个表才能将这两个表链接在一起。也许(仅使用这里的列名)表可以是Battles_Ships_Rel:

代码语言:javascript
运行
复制
Create Table Battles_Ships_Rel (
    battles_ships_rel_id Int,
    battle_name Varchar(40),
    ship_name Varchar(40)
);

这并不理想,因为battle_name和ship_name都引用了两个不同表中具有相同名称但含义不同的列。此外,完整的外部连接将获得您不想要的记录,因为它将从所有3个表中拉出记录,无论它们是否有匹配。如果你只想要瓜达尔卡纳尔岛战役中的战舰,那么你需要一个内部连接(除非没有战舰参战,但我认为情况并非如此)。我们可以将外部连接的类留给ships,因为外部连接是您所要求的,但它应该是一个左外部连接。下面的查询将起作用:

代码语言:javascript
运行
复制
SELECT Ships.name, Classes.displacement, Classes.numGuns
FROM Ships
INNER JOIN Battles_Ships_Rel
  ON Ships.name = Battles_Ships_Rel.ship_name
LEFT INNER JOIN Classes
--all ships, but only classes that have a record for Ships.class
  ON Ships.class = Classes.class 
WHERE Battles_Ships_Rel.battle_name = 'Guadalcanal';

因为在本例中我们在Battles_Ships_Rel中有战斗名称,所以不需要战斗表。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42767958

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档