同じテーブルに2回参加する最良の方法は何ですか?


108

これは少し複雑ですが、2つのテーブルがあります。構造が次のようなものであるとしましょう:

*Table1*
ID
PhoneNumber1
PhoneNumber2

*Table2*
PhoneNumber
SomeOtherField

テーブルは、Table1.PhoneNumber1-> Table2.PhoneNumber、またはTable1.PhoneNumber2-> Table2.PhoneNumberに基づいて結合できます。

次に、PhoneNumber1、PhoneNumber1、PhoneNumber2に対応するSomeOtherField、およびPhoneNumber2に対応するSomeOtherFieldを含む結果セットを取得します。

これを行うには2つの方法を考えました。テーブルを2回結合するか、ON句でORを使用して1回結合するかのどちらかです。

方法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

これは動作するようです。

方法2

なんとなくこのようなクエリを作成するには-

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

私はこれをまだ動作させることができていません。それを行う方法があるかどうかはわかりません。

これを達成するための最良の方法は何ですか?どちらの方法も単純でも直感的でもないように思われます...これを行う簡単な方法はありますか?この要件は通常どのように実装されますか?

回答:


151

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

方法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を指定する必要はありません-これは、LEFTまたはRIGHTを指定していないという事実によって暗示されています
  • プライマリルックアップテーブルにn接尾辞を付けないでください
  • わかりやすくするために複数回使用するテーブルエイリアスのNサフィックス

* DBAが自然キーの更新で頭痛の種を回避する1つの方法は、主キーと外部キーの制約を指定しないことです。これは、DBの設計が悪い場合の問題をさらに悪化させます。私は実際にこれをより頻繁に見ました。


私は自分自身の問題にこのソリューションを使用しました。それは大いに役立ちました。ただし、これを確認する前に、テーブルを相互に結合する必要があるのを確認できる場所に主キーと外部キーを適用しました。なぜこれが悪い考えなのですか?
ボリューム1、

6
@volumeone-私の答えの最後の部分を誤解していると思います。主キーと外部キー良い考えです。それらを回避することは、悪い習慣であり、悪いデザインであり、ただ悪いことです。
Paul Sasik、2014

Perfect ..しかし、なぜこの状況ではエイリアスが必須なのでしょうか。
雷電コア

同じテーブルを2回結合せずにこれを行う方法はありますか?おそらくwhere句で条件を使用します...
JohnOsborne 2018年

5

1つ目は、Phone1または(可能性が高い)phone2のいずれかがnullになり得ない場合を除き、適切です。その場合、内部結合の代わりに左結合を使用します。

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


素晴らしいポイント!これは後で私に大きな頭痛を引き起こしていたでしょう...ありがとう!
froadie

4

UNION2つの結合を組み合わせるために使用できます。

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

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

ああ、私はほぼ反対だと思いました。その場合は、最初の方法のようなものを使用します。回答を編集します。
先のとがっ

3

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

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;

2

最初の方法は適切なアプローチであり、必要なことを行います。ただし、内部結合ではTable1、両方に電話番号が存在する場合にのみ、行が選択されTable2ます。LEFT JOINからすべての行Table1が選択されるようにすることができます。電話番号が一致しない場合、SomeOtherFieldsはnullになります。一致する電話番号が少なくとも1つあることを確認する場合は、次のようにしますWHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

第二の方法は、問題がある可能性があり、次の場合に何が起こるかTable2、両方持ちPhoneNumber1PhoneNumber2?どの行が選択されますか?データ、外部キーなどによっては、これが問題になる場合と問題にならない場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.