2017-03-13 14 views
0

私のデータベースには、Guadalcanalの戦いで戦ったすべての船の銃の名前、変位、および銃の数を記載しなければなりません。このために私は3つのテーブルを使用する必要があります。その名前は船のテーブルから来て、銃の数はクラステーブルから来て、戦闘は戦闘テーブルから来ます。3つのテーブルに対して外部結合を使用する方法。

Select Ships.name, displacement, numGuns 
From (Classes Full Outer Join Ships ON Classes.class = Ships.class), Battles 
Where Battles.name = 'Guadalcanal'; 

私は外が正しく参加し使用していないと思うので、今これは主に動作しません。

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 
); 

ここで私が使用しようとしたクエリがあります。問題は、3つのテーブルに対して外部結合を使用する方法がわかりません。

+0

バトルと他の2つのテーブルとの間には関係がありません。だから、あなたは何を期待していますか?また、その表から列を選択しないでください。それで何がやっているのか、どうやって知っていますか? – APC

+0

最初のテーブルの後に3番目のテーブルのために別の外部結合を追加するだけです。副次的なことに、 'from'節にコンマを置くべきではありません。クエリで作成しているのは、 'Classes'と' Ships'の '完全な結合 'と' Battles'の '十字結合'です。 – Siyual

答えて

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'; 
+0

'WHERE'節で' Battles'を使うと 'OUTER JOIN'が無効になります。これは 'ON'節になければなりません(これは2番目の' 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で始まり、あればBattle_Shipsと一致するものがあればそれにマッチします。どの船も決して戦闘に参加していなかったことを示したかった場合を除いて、完全な外部結合を使用することはほとんどありません(左手側も空になるため)。

+0

これはあなたにとって理にかなっていますか? – DeezCashews

0

まず、テーブルを互いに正確に関連付けるために、各テーブルにプライマリキーが必要です。 classがクラステーブル内で一意で、すべてのShipレコードにClassesテーブルにリストされているクラスがある場合、Classesテーブルのキーとして機能します。クラスに関係なく、すべての船名がユニークでない限り、そのテーブルにプライマリキーが必要です。 Battlesでも主キーが必要です。 BattlesテーブルとShipsテーブルは、お互いに多対多の関係を持つ可能性が非常に高いでしょう。船は複数の戦闘に参加することができ、戦闘は複数の船を持つことができます。これらの2つのテーブルをリンクするには別のテーブルが必要です。おそらく、(あなたがここで持っている唯一の列名を使用して)表は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で戦闘名を持っているので。

関連する問題