Was ist der beste Weg, um zweimal am selben Tisch teilzunehmen?

108

Das ist etwas kompliziert, aber ich habe 2 Tische. Nehmen wir an, die Struktur sieht ungefähr so ​​aus:

*Table1*
ID
PhoneNumber1
PhoneNumber2

*Table2*
PhoneNumber
SomeOtherField

Die Tabellen können basierend auf Table1.PhoneNumber1 -> Table2.PhoneNumber oder Table1.PhoneNumber2 -> Table2.PhoneNumber verknüpft werden.

Jetzt möchte ich eine Ergebnismenge erhalten, die PhoneNumber1, SomeOtherField, das PhoneNumber1, PhoneNumber2 entspricht, und SomeOtherField, das PhoneNumber2 entspricht, enthält.

Ich habe mir zwei Möglichkeiten ausgedacht, dies zu tun - entweder durch zweimaliges Verbinden auf dem Tisch oder durch einmaliges Verbinden mit einem ODER in der ON-Klausel.

Methode 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

Das scheint zu funktionieren.

Methode 2 :

Irgendwie eine Abfrage zu haben, die ein bisschen so aussieht -

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

Ich habe das noch nicht zum Laufen gebracht und bin mir nicht sicher, ob es einen Weg gibt, es zu tun.

Was ist der beste Weg, um dies zu erreichen? Keiner der Wege scheint einfach oder intuitiv zu sein ... Gibt es einen einfacheren Weg, dies zu tun? Wie wird diese Anforderung allgemein umgesetzt?

froadie
quelle

Antworten:

151

Zuerst würde ich versuchen, diese Tabellen umzugestalten, um nicht mehr Telefonnummern als natürliche Schlüssel zu verwenden. Ich bin kein Fan von natürlichen Schlüsseln und dies ist ein großartiges Beispiel dafür. Natürliche Schlüssel, insbesondere Telefonnummern, können sich häufig ändern. Das Aktualisieren Ihrer Datenbank, wenn diese Änderung eintritt, ist ein RIESIGES, fehleranfälliges Problem. * *

Methode 1, wie Sie sie beschreiben, ist jedoch die beste Wahl. Aufgrund des Namensschemas und der kurzen Aliase sieht es etwas knapp aus, aber ... Aliasing ist Ihr Freund, wenn es darum geht, dieselbe Tabelle mehrmals zu verbinden oder Unterabfragen usw. zu verwenden.

Ich würde nur ein bisschen aufräumen:

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

Was ich getan habe:

  • Sie müssen INNER nicht angeben - dies wird dadurch impliziert, dass Sie weder LINKS noch RECHTS angeben
  • Fügen Sie Ihrer primären Nachschlagetabelle kein N-Suffix hinzu
  • N-Suffixieren Sie die Tabellen-Aliase, die Sie mehrmals verwenden werden, um dies deutlich zu machen

* Eine Möglichkeit, wie Datenbankadministratoren die Probleme beim Aktualisieren natürlicher Schlüssel vermeiden können, besteht darin, keine Primärschlüssel und Fremdschlüsseleinschränkungen anzugeben, was die Probleme mit einem schlechten Datenbankdesign weiter verschärft. Ich habe das tatsächlich öfter gesehen als nicht.

Paul Sasik
quelle
Ich habe diese Lösung gerade für mein eigenes Problem verwendet. Es hat sehr geholfen. Bevor ich dies sah, habe ich jedoch Primärschlüssel und Fremdschlüssel angewendet, wo immer ich Tabellen sehen konnte, die miteinander verbunden werden müssen. Warum ist das eine schlechte Idee?
Band eins
6
@volumeone - Ich denke, Sie haben den letzten Teil meiner Antwort möglicherweise falsch verstanden. Primär- und Fremdschlüssel sind eine gute Idee. Sie zu vermeiden ist schlechte Praxis, schlechtes Design und einfach nur schlecht.
Paul Sasik
Perfekt ... aber warum sind Aliase in dieser Situation ein Muss?
Raiden Core
Gibt es eine Möglichkeit, dies zu tun, ohne zweimal am selben Tisch teilzunehmen? Vielleicht verwenden Sie eine Bedingung in der where-Klausel ...
JohnOsborne
5

Das erste ist gut, es sei denn, entweder Telefon1 oder (wahrscheinlicher) Telefon2 kann null sein. In diesem Fall möchten Sie einen linken Join anstelle eines inneren Joins verwenden.

Es ist normalerweise ein schlechtes Zeichen, wenn Sie eine Tabelle mit zwei Telefonnummernfeldern haben. Normalerweise bedeutet dies, dass Ihr Datenbankdesign fehlerhaft ist.

HLGEM
quelle
Toller Punkt! Das hätte mir später große Kopfschmerzen bereitet ... danke!
Froadie
4

Sie können UNIONzwei Verknüpfungen kombinieren:

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
Spitze
quelle
1
Ich habe darüber nachgedacht, aber ich brauche es, um es als einzelne denormalisierte Aufzeichnung zurückzugeben ...
froadie
Oh OK, ich habe so ziemlich das Gegenteil angenommen. Wenn das der Fall ist, würde ich es mit so etwas wie Ihrer ersten Methode machen. Ich werde meine Antwort bearbeiten.
Pointy
3

Mein Problem bestand darin , den Datensatz auch dann anzuzeigen, wenn keine oder nur eine Telefonnummer vorhanden ist (vollständiges Adressbuch). Deshalb habe ich einen LEFT JOIN verwendet, der alle Datensätze von links nimmt, auch wenn rechts kein entsprechender vorhanden ist. Für mich funktioniert dies in Microsoft Access SQL (sie erfordern die Klammer!)

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;
F1iX
quelle
2

Die erste Methode ist der richtige Ansatz und wird das tun, was Sie brauchen. Bei den inneren Verknüpfungen wählen Sie jedoch nur dann Zeilen aus, Table1wenn beide Telefonnummern in vorhanden sind Table2. Möglicherweise möchten Sie dies tun, LEFT JOINdamit alle Zeilen aus Table1ausgewählt werden. Wenn die Telefonnummern nicht übereinstimmen, ist das SomeOtherFields null. Wenn Sie sicherstellen möchten, dass Sie mindestens eine passende Telefonnummer haben, können Sie dies tunWHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

Die zweite Methode könnte ein Problem haben: Was passiert, wenn Table2beide PhoneNumber1und PhoneNumber2? Welche Zeile wird ausgewählt? Abhängig von Ihren Daten, Fremdschlüsseln usw. kann dies ein Problem sein oder auch nicht.

Nelson Rothermel
quelle