在我的数据库中,我必须列出在瓜达尔卡纳尔岛战役中战斗过的所有船只的名称、排水量和火炮数量。为此,我需要使用3个表。名称来自舰船表,枪炮数量和排水量来自Classes表,战斗来自battles表。
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
);下面是我尝试使用的一个查询:
Select Ships.name, displacement, numGuns
From (Classes Full Outer Join Ships ON Classes.class = Ships.class), Battles
Where Battles.name = 'Guadalcanal';现在,这不起作用,主要是因为我认为我没有正确地使用外部连接。问题是我不知道如何对3个表使用外部连接。
发布于 2017-03-14 00:02:00
首先,确定您的主要信息来源在哪里。在这里,您正在寻找一场战斗以及相关的舰船及其类别。外部联接意味着它将返回一端,即使另一端没有匹配项也是如此。在这种情况下,如果你从战斗开始,你只需要匹配的船,所以:
select b.name
from Battles b
inner join Ships s on b.name = s.battle_name我不认为你有任何东西可以把船和战斗联系起来。我的猜测是,您缺少一个将舰船与战斗相匹配的XREF表。
Battle_Ships
+++++++++++++++
battle | ship
+++++++++++++++
battle1 | ship1
battle1 | ship2
battle1 | ship3
battle2 | ship3
battle2 | ship4有了这个,你就可以像这样得到战斗和船:
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然后你会想要得到船的类,所以你可以得到位移,但我猜这可能不存在,所以你会想要外连接它
select s.name, c.numGuns, c.displacement
from Ships s
left outer join Classes c on s.class = c.class总而言之,你会得到类似这样的东西:
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 (如果有),匹配船只(如果有),然后匹配类。您几乎不想使用完整的外部连接,除非您还想显示哪些船从未在战斗中(因为这样会允许左侧也是空的)。
发布于 2017-03-14 00:01:18
战斗和职业/舰船共享的密钥是什么?一旦你有了它,下面的方法就应该起作用了。此编辑假设船舶是与Battle共享的关键。
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';发布于 2017-03-14 07:57:04
首先,您希望每个表中都有一个主键,以便您可以准确地将这些表彼此关联起来。如果class在classes表中是唯一的,并且每个Ship记录都有一个Classes表中列出的类,那么它将作为Classes表中的一个键。除非每个ship名称都是唯一的,否则您还需要在该表中有一个主键。主键在战斗中也是需要的。战斗表和舰船表之间很可能存在多对多的关系。一艘船可以处于多个战斗中,一场战斗可以有多艘船。需要另一个表才能将这两个表链接在一起。也许(仅使用这里的列名)表可以是Battles_Ships_Rel:
Create Table Battles_Ships_Rel (
battles_ships_rel_id Int,
battle_name Varchar(40),
ship_name Varchar(40)
);这并不理想,因为battle_name和ship_name都引用了两个不同表中具有相同名称但含义不同的列。此外,完整的外部连接将获得您不想要的记录,因为它将从所有3个表中拉出记录,无论它们是否有匹配。如果你只想要瓜达尔卡纳尔岛战役中的战舰,那么你需要一个内部连接(除非没有战舰参战,但我认为情况并非如此)。我们可以将外部连接的类留给ships,因为外部连接是您所要求的,但它应该是一个左外部连接。下面的查询将起作用:
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中有战斗名称,所以不需要战斗表。
https://stackoverflow.com/questions/42767958
复制相似问题