在我的数据库中,我必须列出在Guadalcanal战斗中所有战斗的船只的名称,位移和枪支数量。为此,我需要使用3个表。这个名字来自船舶表,枪支数量和位移来自Classes表,战斗来自战斗表。
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个表的外连接。
答案 0 :(得分:2)
首先确定您的主要信息来源。在这里,您正在寻找一场战斗以及相关的船只和他们的班级。 OUTER JOIN表示即使另一侧没有匹配也会返回一侧。在这种情况下,如果你从战斗开始,你只需要匹配的船只:
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'
同样,左外连接意味着匹配左侧并且如果存在则返回右侧。在这里我们从Battle开始,然后匹配Battle_Ships,如果有的话,匹配Ships如果有的话,那么Classes。你几乎从不想要使用完整的外部连接,除非你也想要展示哪些船只从未在战斗中(因为那样它也允许左侧也是空的)。
答案 1 :(得分:0)
战斗和课程/船舶共享的关键是什么?一旦你有了,以下应该工作。此编辑假定Ships与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';
答案 2 :(得分:0)
首先,您希望在每个表中都有一个主键,以便您可以准确地将表相互关联。如果class在classes表中是唯一的,并且每个Ship记录都有一个在Classes表中列出的类,那么它将作为Classes表中的键。除非每个船名,无论是哪一类,都是唯一的,否则您也需要该表中的主键。战斗也需要一把钥匙。 战斗和船舶表很可能彼此之间存在多对多的关系。一艘船可以进行多场战斗,一场战斗可以有多艘战舰。需要另一个表来将这两个表链接在一起。也许(仅使用此处的列名称)表可以是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都引用了2个不同表中具有相同名称但含义不同的列。此外,完全外部联接将获得您不想要的记录,因为它将从所有3个表中提取记录,无论它们是否匹配。如果你只想要来自瓜达尔卡纳尔战役的船只,那么你想要一个内部连接(除非没有船只参加那场战斗,但我认为情况并非如此)。我们可以将Classes外部连接到船只,因为外部连接是您请求的,但它应该是左外连接。以下查询将起作用:
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中有战斗名称,因此不需要战斗表。