2010-11-24 18 views
75

これは少し複雑ですが、私は2つのテーブルを持っています。 > Table2.PhoneNumber、またはTable1.PhoneNumber2 - - > Table2.PhoneNumber表はTable1.PhoneNumber1に基づいて結合することができる同じテーブルに2回参加する最善の方法は何ですか?

*Table1* 
ID 
PhoneNumber1 
PhoneNumber2 

*Table2* 
PhoneNumber 
SomeOtherField 

:の構造は、このようなものであるとしましょう。

ここで、PhoneNumber1、PhoneNumber2に対応するSomeOtherField、PhoneNumber2に対応するSomeOtherFieldを含む結果セットを取得します。

私はこれを行う2つの方法を考えました - テーブルに2回参加するか、ON句でORと一度参加するかのどちらかです。

方法1

SELECT t1.PhoneNumber1, t1.PhoneNumber2, 
    t2.SomeOtherFieldForPhone1, t3.someOtherFieldForPhone2 
FROM Table1 t1 
INNER JOIN Table2 t2 
    ON t2.PhoneNumber = t1.PhoneNumber1 
INNER JOIN Table2 t3 
    ON t3.PhoneNumber = t1.PhoneNumber2 

これは動作するようです。私はまだ仕事にこれをもらっていないと私はあるかどうかわからない

SELECT ... 
FROM Table1 
INNER JOIN Table2 
    ON Table1.PhoneNumber1 = Table2.PhoneNumber OR 
     Table1.PhoneNumber2 = Table2.PhoneNumber 

- 何とかビットのこのようなクエリを持つように

方法2それを行う方法。

これを達成する最も良い方法は何ですか?どちらの方法も単純で直感的ではないようです...これを行うもっと簡単な方法はありますか?この要件は一般にどのように実装されていますか?

答えて

103

まず、これらのテーブルをリファクタリングして、電話番号を自然なキーとして使用しないようにします。私は自然なキーのファンではない、そして、これはなぜ素晴らしい例です。ナチュラルキー、特に電話番号のようなものは、頻繁に変わることがあります。その変更が発生したときにデータベースを更新すると、エラーが発生しやすくなります。 *

方法1これはあなたの最善の策です。それは命名計画と短いエイリアスのために少し簡潔に見えますが...エイリアシングは、同じテーブルを複数回結合するかサブクエリなどを使用するときにあなたの友人です

私はちょうどきれいな物事ビットでしょう

:私は何

SELECT t.PhoneNumber1, t.PhoneNumber2, 
    t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2 
FROM Table1 t 
JOIN Table2 t1 ON t1.PhoneNumber = t.PhoneNumber1 
JOIN Table2 t2 ON t2.PhoneNumber = t.PhoneNumber2 

  • INNERを指定する必要はありません - それはあなたが左または右を指定していないという事実によって暗示されます
  • プライマリルックアップテーブルにn接尾辞を付けないでください。
  • N接頭辞明示的に複数回使用するテーブルエイリアス

* DBAがナチュラルキーの更新の頭痛を回避する1つの方法は、プライマリキーと外部キー制約を指定しないことです。私は実際にこれを見たことがあります。

+0

私はちょうど私自身の問題のために、このソリューションを使用しましたのMicrosoft Access SQLで動作します。それは多くの助けとなりました。しかし、これを見る前に、互いに結合する必要のあるテーブルを見ることができるところで、私は主キーと外部キーを適用しました。なぜこれは悪い考えですか? –

+6

@volumeone - あなたは私の答えの最後の部分を誤解しているかもしれないと思います。プライマリキーと外部キー**は**良い考えです。それらを避けることは、貧しい習慣であり、悪い設計であり、ひどい悪いことです。 –

+0

完璧ですが、なぜこのような状況でエイリアスが必要なのでしょうか? –

2

最初の方法は適切なアプローチであり、必要な処理を行います。ただし、両方の電話番号がTable2に存在する場合は、内部結合ではTable1の行のみを選択します。 Table1のすべての行が選択されるように、LEFT JOINを実行するとよいでしょう。電話番号が一致しない場合、SomeOtherFieldはnullになります。あなたは少なくとも一つのマッチングの電話番号を持っていることを確認したい場合は、問題を抱えている可能性がWHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

第二の方法を行うことができ:Table2は両方PhoneNumber1PhoneNumber2を持っている場合はどうなりますか?どの行が選択されますか?あなたのデータ、外部キーなどに応じて、これは問題になるかもしれません。

2

次の2つを組み合わせることUNIONを使用することができ加入:PHONE1または(可能性が高い)phone2のいずれかがNULLとなる可能性がある場合を除き

SELECT Table1.PhoneNumber1 as PhoneNumber, Table2.SomeOtherField as OtherField 
    FROM Table1 
    JOIN Table2 
    ON Table1.PhoneNumber1 = Table2.PhoneNumber 
UNION 
SELECT Table1.PhoneNumber2 as PhoneNumber, Table2.SomeOtherField as OtherField 
    FROM Table1 
    JOIN Table2 
    ON Table1.PhoneNumber2 = Table2.PhoneNumber 
+0

私はこれについて考えましたが、私はそれを単一の非正規化されたレコードとして返す必要があります... – froadie

+0

ああ、私はかなり反対を仮定しました。その場合、私はあなたの最初の方法のようなものを使ってやります。私は私の答えを編集します。 – Pointy

4

は、最初は良いです。その場合は、内部結合の代わりに左結合を使用します。

2つの電話番号フィールドを持つテーブルを使用しているときは、通常、悪い兆候です。通常、これはデータベース設計に欠陥があることを意味します。

+0

大きなポイント!これは後で大きな頭痛を引き起こしたでしょう...ありがとう! – froadie

1

私の問題はであり、電話番号が1つでも存在しない場合でも、表示されます。(フルアドレス帳)。したがって、右に対応するものがない場合でも、左からすべてのレコードを取るLEFT JOINを使用しました。私にとって、これは(彼らは括弧が必要です!)

SELECT t.PhoneNumber1, t.PhoneNumber2, t.PhoneNumber3 
    t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2, t3.someOtherFieldForPhone3 
FROM 
(
(
    Table1 AS t LEFT JOIN Table2 AS t3 ON t.PhoneNumber3 = t3.PhoneNumber 
) 
LEFT JOIN Table2 AS t2 ON t.PhoneNumber2 = t2.PhoneNumber 
) 
LEFT JOIN Table2 AS t1 ON t.PhoneNumber1 = t1.PhoneNumber; 
関連する問題