Datenbankdesign: Zwei 1 bis viele Beziehungen zu derselben Tabelle

20

Ich muss eine Situation modellieren, in der ich eine Tabelle Chequing_Account (die Budget, IBAN-Nummer und andere Details des Kontos enthält) habe, die mit zwei verschiedenen Tabellen Person und Corporation verknüpft sein muss, die beide 0, 1 oder viele Chequing-Konten haben können.

Mit anderen Worten, ich habe zwei 1-zu-viele-Beziehungen mit demselben Tabellen-Chequing-Konto

Ich würde gerne Lösungen für dieses Problem hören, die die Normalisierungsanforderungen berücksichtigen. Die meisten Lösungen, die ich gehört habe, sind:

1) Finden Sie eine gemeinsame Entität, zu der sowohl Person als auch Firma gehören, und erstellen Sie eine Verknüpfungstabelle zwischen dieser und der Tabelle Chequing_Account. Dies ist in meinem Fall nicht möglich, und selbst wenn ich das allgemeine Problem und nicht diese spezifische Instanz lösen möchte.

2) Erstellen Sie zwei Verknüpfungstabellen PersonToChequingAccount und CorporationToChequingAccount, die die beiden Entitäten mit den Kontrollkonten in Beziehung setzen. Ich möchte jedoch nicht, dass zwei Personen dasselbe Chequing-Konto haben, und ich möchte nicht, dass eine natürliche Person und eine Firma ein Chequing-Konto teilen! siehe dieses Bild

http://i41.tinypic.com/35i6kbk.png

3) Erstellen Sie zwei Fremdschlüssel in Chequing Account, die auf Corporation und Natural Person verweisen. Allerdings würde ich damit erzwingen, dass eine Person und eine Firma viele Chequing Accounts haben können. Ich müsste jedoch manuell sicherstellen, dass nicht beide Beziehungen für jede ChequingAccount-Zeile auf verweisen Körperschaft und natürliche Person, weil ein Girokonto entweder eine Körperschaft oder eine natürliche Person ist. siehe dieses Bild

http://i40.tinypic.com/1rpv9z.png

Gibt es eine andere sauberere Lösung für dieses Problem?

Dendini
quelle
Haben Sie darüber nachgedacht, zB einen OwnerTypeIDin der ChecquingAccountTabelle zu haben, mit 1=Corporationund 2=NaturalPerson? Auf diese Weise benötigen Sie nur eine OwnerIDin der ChecquingAccountTabelle, die Sie zusammen mit der indizieren können OwnerTypeID.
RoKa
Ich muss nicht nur wissen, ob es sich um ein Unternehmen oder eine natürliche Person handelt, sondern auch die jeweilige ID, also brauche ich eine ID-Nummer und nicht nur einen Wert von 1 oder 2! Lösung 3 ist das, was ich hier gefunden habe. Ich habe zwei Spalten mit IDs für Unternehmen oder natürliche Personen
Dendini
2
Ja, die Lösung ist eine gültige Option. In den meisten DBMS können Sie durchsetzen, dass nur einer der beiden FKs mit einer Prüfbedingung "aktiv" ist: CHECK (CorporationID IS NOT NULL AND NaturalPersonID IS NULL OR CorporationID IS NULL AND NaturalPersonID IS NOT NULL)Ich bevorzuge jedoch Lösung 1 (aber das bin nur ich). Es ist viel "sauberer".
ypercubeᵀᴹ
Ja, ich verstehe, aber Sie könnten ChecquingAccounteinen Datensatz von OwnerTypeID=1und in der Tabelle haben OwnerID=123, der angibt, dass es sich um einen Typ handelt Corporation, daher ID 123in der CorporationTabelle. Die OwnerTypeID gibt Auskunft darüber, welche Tabelle Sie haben, und die OwnerID gibt Auskunft über die ID in dieser Tabelle.
RoKa
1
Wie ist Option 1 unmöglich? Das Wort "Corporation" bedeutet im Grunde genommen "ein Unternehmen, das rechtlich eine Person ist". Nenne es einen CustomersTisch.
Jon of All Trades

Antworten:

15

Relationale Datenbanken sind nicht dafür ausgelegt, mit dieser Situation perfekt umzugehen. Sie müssen entscheiden, was für Sie am wichtigsten ist, und dann Ihre Kompromisse eingehen. Sie haben mehrere Ziele:

  • Behalten Sie die dritte Normalform bei
  • Aufrechterhaltung der referenziellen Integrität
  • Behalten Sie die Einschränkung bei, dass jedes Konto entweder einem Unternehmen oder einer natürlichen Person gehört.
  • Erhalten Sie die Fähigkeit, Daten einfach und direkt abzurufen

Das Problem ist, dass einige dieser Ziele miteinander konkurrieren.

Subtypisierungslösung
Sie können eine Subtypisierungslösung auswählen, bei der Sie einen Supertyp erstellen, der sowohl Unternehmen als auch Personen umfasst. Dieser Supertyp hätte wahrscheinlich einen zusammengesetzten Schlüssel des natürlichen Schlüssels des Untertyps plus ein Partitionierungsattribut (z customer_type. B. ). Dies ist für die Normalisierung in Ordnung und ermöglicht es Ihnen, die referenzielle Integrität sowie die Einschränkung durchzusetzen, dass Unternehmen und Personen sich gegenseitig ausschließen. Das Problem ist, dass dies das Abrufen von Daten erschwert, da Sie immer nach dem customer_typeZeitpunkt verzweigen müssen, an dem Sie das Konto dem Kontoinhaber hinzufügen. Dies bedeutet wahrscheinlich, UNIONdass Sie eine Menge sich wiederholender SQL-Anweisungen in Ihrer Abfrage verwenden und verwenden müssen.

Zwei Fremdschlüssel Lösung
Sie könnten eine Lösung wählen , wo Sie halten zwei Fremdschlüssel in Ihrem Konto Tisch, ein körperschaft und eine zu Person. Diese Lösung ermöglicht es Ihnen auch, die referenzielle Integrität, Normalisierung und gegenseitige Ausschließlichkeit aufrechtzuerhalten. Es hat auch den gleichen Nachteil beim Abrufen von Daten wie die Subtypisierungslösung. Tatsächlich ist diese Lösung genau wie die Untertypisierungslösung, mit der Ausnahme, dass Sie das Problem haben, Ihre Verknüpfungslogik "früher" zu verzweigen.

Dennoch würden viele Datenmodellierer diese Lösung aufgrund der Art und Weise, in der die gegenseitige Ausschließlichkeitsbeschränkung durchgesetzt wird, als der Subtypisierungslösung unterlegen betrachten. In der Subtypisierungslösung verwenden Sie Schlüssel, um die gegenseitige Exklusivität zu erzwingen. In der Lösung mit zwei Fremdschlüsseln verwenden Sie eine CHECKEinschränkung. Ich kenne einige Leute, die eine ungerechtfertigte Voreingenommenheit gegenüber Prüfungsbeschränkungen haben. Diese Leute würden die Lösung bevorzugen, die die Einschränkungen in den Schlüsseln beibehält.

Lösung für das Partitionierungsattribut "Denormalized" (Denormalisiert)
Es gibt eine andere Option, bei der Sie eine einzelne Fremdschlüsselspalte in der Tabelle des Prüfkontos behalten und in einer anderen Spalte erfahren, wie die Fremdschlüsselspalte (RoKa's) zu interpretieren istOwnerTypeIDSäule). Dadurch wird die Supertyp-Tabelle in der Untertypisierungslösung im Wesentlichen eliminiert, indem das Partitionierungsattribut für die untergeordnete Tabelle denormalisiert wird. (Beachten Sie, dass dies gemäß der formalen Definition keine reine "Denormalisierung" ist, da das Partitionierungsattribut Teil eines Primärschlüssels ist.) Diese Lösung erscheint recht einfach, da keine zusätzliche Tabelle vorhanden ist, um mehr oder weniger dasselbe zu tun Reduziert die Anzahl der Fremdschlüsselspalten auf eins. Das Problem bei dieser Lösung besteht darin, dass das Verzweigen der Abruflogik nicht vermieden wird und darüber hinaus die deklarative referenzielle Integrität nicht aufrechterhalten werden kann . SQL-Datenbanken können keine einzelne Fremdschlüsselspalte für eine von mehreren übergeordneten Tabellen verwalten.

Shared Primary Key Domain-Lösung
Eine Möglichkeit, mit diesem Problem umzugehen, besteht manchmal darin, einen einzelnen ID-Pool zu verwenden, damit für eine bestimmte ID nicht verwechselt werden kann, ob sie zu einem Subtyp oder einem anderen gehört. In einem Bankenszenario würde dies wahrscheinlich ganz natürlich funktionieren, da Sie nicht die gleiche Bankkontonummer sowohl für ein Unternehmen als auch für eine natürliche Person vergeben. Dies hat den Vorteil, dass kein Partitionierungsattribut erforderlich ist. Sie können dies mit oder ohne eine Super-Typ-Tabelle tun. Wenn Sie eine Supertyp-Tabelle verwenden, können Sie deklarative Einschränkungen verwenden, um die Eindeutigkeit zu erzwingen. Andernfalls müsste dies verfahrensrechtlich durchgesetzt werden. Diese Lösung ist normalisiert, ermöglicht es Ihnen jedoch nicht, die deklarative referenzielle Integrität beizubehalten, es sei denn, Sie führen die Supertyp-Tabelle. Es wird immer noch nichts unternommen, um eine komplexe Abruflogik zu vermeiden.

Sie sehen also, dass es nicht wirklich möglich ist, ein sauberes Design zu haben, das alle Regeln einhält, und gleichzeitig den Datenabruf einfach zu halten. Sie müssen entscheiden, wo Ihre Kompromisse sein werden.

Joel Brown
quelle
Meine Lösung Nr. 2 zu welcher Ihrer vier Gruppen gehört? Die "Lösung für
denormalisierte
@dendini - Ihre Lösung Nummer 2 passt nicht zu den von mir beschriebenen Lösungen. Dies liegt daran, dass es nicht mit der Anforderung eines Kontos einer juristischen Person übereinstimmt. So wie Sie die Primärschlüssel der Zwischentabellen definiert haben, handelt es sich um viele-zu-viele-Schnittmengen. Wenn die Primärschlüssel nur corporation_id und person_iddann wären, hätten Sie im Wesentlichen die Untertypisierungslösung, mit der Ausnahme, dass die Supertypentabelle in zwei Teile geteilt und der Fremdschlüssel invertiert worden wäre, sodass die Benutzer nicht über mehrere Konten verfügen könnten. Diese Art der Niederlage den Zweck.
Joel Brown
Tolle Erklärung. @JoelBrown, was sind die Auswirkungen auf die Leistung der Lösung "Zwei Fremdschlüssel" in Bezug auf die Abfrage? Wenn man bedenkt, dass es anstelle von 2 auch 6 oder mehr Fremdschlüssel geben kann: Würden Sie diesen Ansatz dennoch empfehlen oder sich eher einem anderen zuwenden?
Amadeo Gallardo
1
@ MadeoGallardo Die Antwort ist "es kommt darauf an". Das Abfragen nach einem Schlüssel ist immer sehr effizient, da Sie im Allgemeinen zumindest auf einen Index-Scan zählen können, wenn nicht auf einen Suchvorgang, und dies sind schnelle Vorgänge. Das Problem tritt auf, wenn Sie in der Lösung mit zwei Fremdschlüsseln eine Abfrage über beide Schlüssel durchführen . Hier fordern Sie den Abfrageoptimierer auf, eine Entweder-Oder-Operation auszuführen. Bestenfalls verdoppelt dies die Kosten der Abfrage, normalerweise etwas schlimmer, da Sie erst nach einem Schlüssel und dann nach dem anderen abfragen und dann die Ergebnisse zusammenführen müssen.
Joel Brown
@JoelBrown Denormalisierte Zukunft SQL - Versionen sollten diesen Ansatz ermöglicht durch die Definition einer Verbindung Fremdschlüssel ermöglicht basiert auf zwei Säulen RefIDund RefTablewo RefTableist eine feste Kennung, identifiziert die Zieltabelle. Es gibt viele Anwendungsfälle für diesen Schlüsseltyp und es ist zu viel, um 10 oder mehr Zuordnungs- / Subtyp-Tabellen zu verwalten, um die Integrität durchzusetzen. Für diese Fälle habe ich das keyselbst erstellt.
13.