2017-03-13 33 views
0

在我的數據庫中,我必須列出所有在瓜達爾卡納爾海戰中作戰的船隻的名稱,位移和槍支數量。爲此,我需要使用3個表格。這個名字來自船舶表,槍的數量和位移來自Classes表,戰鬥來自戰鬥表。如何在3個表上使用外部聯接。

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

BATTLES和其他兩張表之間沒有任何關係。那麼你期望發生什麼?另外,您不要從該表中選擇任何列。那麼你怎麼知道它在做什麼? – APC

+0

只需在第一個表格之後爲第三個表格添加另一個外部聯接。一個側面說明,你不應該在'from'子句中使用逗號。你在查詢中創建的是'Classes'和'Ships'之間的'full join'和''Battles''上的'cross join'。 – Siyual

回答

0

戰鬥和課堂/船舶共享的關鍵是什麼?一旦你有了,以下應該工作。這些編輯假設船舶與戰鬥共享密鑰。

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

在'WHERE'子句中使用'戰鬥'會使'OUTER JOIN'失效。這*必須*在'ON'子句中(你也從第二個'FULL JOIN'中丟失了)。 – Siyual

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_Ships,如果有的話,如果有船舶,則匹配船隻,然後是類別。除非你也想顯示哪艘戰艦從來沒有參加過戰鬥,否則你幾乎不會想要使用完整的外部連接(因爲這樣也可以讓左側空着)。

+0

這對你有意義嗎? – DeezCashews

0

首先,您希望每個表中都有一個主鍵,以便您可以準確地將這些表彼此關聯。如果類在類表中是唯一的,並且每個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個表中提取記錄,而不管它們是否匹配。如果你只想從瓜達爾卡納爾戰役中獲得船隻,那麼你需要一個內部連接(除非沒有船隻在這場戰鬥中作戰,但我認爲情況並非如此)。我們可以將類外部連接到船舶,因爲外部連接是您所要求的,但它應該是左側外部連接。下面的查詢將工作:不需要

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在這個例子中進行戰鬥的名稱。