Wenn eine relationale Datenbank erstellt werden soll, ist es sehr hilfreich, zunächst (a) eine Analyse des interessierenden Geschäftskontexts durchzuführen, um ein konzeptionelles Schema in Bezug auf Entitätstypen abzugrenzen und deren Eigenschaften und Zuordnungen zuvor zu überprüfen (b) Denken in Tabellen, Spalten und Einschränkungen - Aspekte, die der logischen Ebene entsprechen -. Nach dieser Vorgehensweise ist es viel simplier die erfassen Bedeutung des Business - Bereichs mit Genauigkeit und dann reflektieren sie in einem tatsächlichen, auch gezwungen, SQL-DDL - Design.
Einer der zahlreichen Vorteile des relationalen Paradigmas besteht darin, dass es die Verwaltung der Daten in ihrer natürlichen Struktur ermöglicht. Daher muss man eine solche Struktur „finden“, bevor man relationale Instrumente einsetzt, um sie zu verwalten. Es spielt keine Rolle, ob sich das fragliche Szenario auf ein persönliches Projekt bezieht (wie Sie in Kommentaren hervorgehoben haben): Je realistischer Sie es definieren, desto mehr lernen Sie aus seiner Entwicklung (wenn dies der Zweck dieser Bemühungen ist). Natürlich kann sich aus einem realistischen persönlichen Projekt ein kommerzielles Projekt mit relativ geringen Anpassungen entwickeln.
Geschäftsregeln
Um einen ersten Fortschritt zu präsentieren, den Sie möglicherweise als Referenz verwenden möchten, habe ich einige der Geschäftsregeln auf konzeptioneller Ebene formuliert, die zu den wichtigsten gehören, und sie werden wie folgt aufgelistet:
- Eine Person besitzt null, eins oder viele Konten
- Eine Person unterscheidet sich hauptsächlich durch ihre ID
- Eine Person wird abwechselnd zeichnet sich durch sein / ihr Vorname , Nachname , Geburtsdatum und Geschlecht
- Eine Organisation besitzt null, eins oder viele Konten
- Eine Organisation unterscheidet sich hauptsächlich durch ihre ID
- Eine Organisation wird abwechselnd durch ihren Namen unterschieden
- Eine Organisation beginnt mit einem Gründungsdatum
- Ein Konto ist der Übertragende bei Null-Eins-oder-Viele- Überweisungen
- Ein Konto ist der Transferee bei Null-Eins-oder-Viele- Überweisungen
- Ein Konto wird hauptsächlich durch seine Nummer identifiziert
- Ein Konto wird zu einem genauen Erstellungsdatum ausgestellt
- Bei einer Übertragung der Übertragenden muss von dem verschieden sein Transferee
- Eine Person kann sich über das Benutzerprofil null oder eins anmelden
Da die Verbände -oder relationships- (1) zwischen Person und Konto und (2) zwischen Organisation und Konto sehr ähnlich ist, diese Tatsache zeigt , dass Person und Konto Einheit sind Subtypen von Partei (grundsätzlich entweder eine Einzelperson oder eine Gruppe von Personen) , was wiederum ihr Entity- Supertyp ist . Dies ist eine klassische Informationsstruktur, die sehr häufig in mehreren konzeptionellen Modellen unterschiedlicher Art auftritt. Auf diese Weise können zwei neue Regeln geltend gemacht werden:
- Ein PartyType klassifiziert null, eins oder viele Parteien
- Eine Partei ist entweder eine Person oder eine Organisation
Und zwei der vorherigen Geschäftsregeln können zu einer einzigen zusammengefasst werden:
- Eine Partei besitzt null, eins oder viele Konten
Was auch unter dem Gesichtspunkt des Entitätstyps Konto angegeben werden kann:
- Ein Konto gehört genau einer Partei
Expository IDEF1X-Diagramm
Infolgedessen habe ich ein Expository- Diagramm (vereinfacht) IDEF1X † erstellt , das die oben formulierten Regeln zusammenfasst. Es ist in Abbildung 1 dargestellt :
Partei, Person und Organisation: Supertyp-Subtyp-Struktur
Wie gezeigt Person
und Organization
als sich gegenseitig ausschließende Subtypen von dargestellt Party
.
Der Party
Supertyp enthält einen Diskriminator (dh PartyTypeCode
) und alle Eigenschaften (oder Attribute), die seinen Untertypen gemeinsam sind, die wiederum die Eigenschaften haben, die für jeden von ihnen gelten.
Konto
Der Account
Entitätstyp ist direkt mit verbunden Party
, wodurch eine nachfolgende Verbindung zwischen (i) Account
und Person
und zwischen (ii) Account
und hergestellt wird Organization
.
Da es möglich ist , dass in der realen Welt, (a) eine Bank ist Account
nicht übertragbar, dh sein Owner
kann und ändern (b) eine Account
kann nicht ohne eine, gegenwärtige oder aktiviert beginnen Owner
, der Primärschlüssel dieses Entitätstyp kann bestehen aus die Eigenschaften PartyId
und AccountNumber
, daher sollten Sie das Szenario noch genauer analysieren, um diesen Punkt mit hoher Präzision zu definieren.
Transfer
Auf der anderen Seite, die Transfer
aus Entitätstyp stellt ein zusammengesetzter Primärschlüssel von drei Eigenschaften auf, dh TransferorAccountNumber
, TransfereeAccountNumber
( Rollennamen mir jeden von beiden zu unterscheiden zugeordnet Account
Eigenschaften in jeder beteiligten Transfer
Instanz) und TransferDateTime
(die die exaxct erzählen Sofort , wenn ein Transfer
Auftreten war durchgeführt).
Faktoren zu AccountNumbers
Beachten Sie auch, dass in tatsächlichen Bankensystemen das Format eines AccountNumber
Datenpunkts normalerweise komplexer ist als ein „bloßer“ ganzzahliger Wert. Es gibt verschiedene Formatvereinbarungen, z. B. die, die der durch die Norm ISO 13616 definierten internationalen Bankkontonummer (IBAN) entspricht. Dieser Aspekt impliziert offensichtlich, dass die (1) konzeptionelle Analyse und die späteren (2) logischen Definitionen einen viel umfassenderen Ansatz erfordern.
Illustrative logische SQL-DDL-Deklarationen
Dann habe ich als Ableitung von der vorherigen Analyse ein logisches Design deklariert, in dem
- Jede Tabelle repräsentiert einen Entitätstyp.
- Jede Spalte steht für eine Eigenschaft des jeweiligen Entitätstyps und
- Es werden (deklarativ) mehrere Einschränkungen eingerichtet, um sicherzustellen, dass die in allen Tabellen enthaltenen Zusicherungen in Form von Zeilen den auf der konzeptionellen Ebene festgelegten Geschäftsregeln entsprechen.
Ich habe Anmerkungen als Kommentare geliefert, die einige der Merkmale erläutern, die ich im Hinblick auf die oben erwähnte Struktur, die unten gezeigt wird, für besonders wichtig halte:
-- You have to determine which are the most fitting
-- data types and sizes for all your table columns
-- depending on the business context characteristics.
-- Also, you should make accurate tests to define the
-- most convenient physical implementation settings; e.g.,
-- a good INDEXing strategy based on query tendencies.
-- As one would expect, you are free to make use of
-- your preferred (or required) naming conventions.
CREATE TABLE PartyType (
PartyTypeCode CHAR(1) NOT NULL, -- This one is meant to contain the meaningful values 'P', for 'Person', and 'O' for 'Organization'.
Name CHAR(30) NOT NULL,
--
CONSTRAINT PartyType_PK PRIMARY KEY (PartyTypeCode)
);
CREATE TABLE Party ( -- Represents the supertype.
PartyId INT NOT NULL,
PartyTypeCode CHAR(1) NOT NULL, -- Denotes the subtype discriminator.
CreatedDateTime TIMESTAMP NOT NULL,
Etcetera CHAR(30) NOT NULL,
--
CONSTRAINT Party_PK PRIMARY KEY (PartyId),
CONSTRAINT PartyToPartyType_FK FOREIGN KEY (PartyTypeCode)
REFERENCES PartyType (PartyTypeCode)
);
CREATE TABLE Person ( -- Stands for a subtype.
PersonId INT NOT NULL, -- To be CONSTRAINed as PRIMARY KEY and FOREIGN KEY at the same time, enforcing an association cardinality of one-to-zero-or-one from Party to Person.
FirstName CHAR(30) NOT NULL,
LastName CHAR(30) NOT NULL,
GenderCode CHAR(3) NOT NULL,
BirthDate DATE NOT NULL,
Etcetera CHAR(30) NOT NULL,
--
CONSTRAINT Person_PK PRIMARY KEY (PersonId),
CONSTRAINT Person_AK UNIQUE ( -- Composite ALTERNATE KEY.
FirstName,
LastName,
GenderCode,
BirthDate
),
CONSTRAINT PersonToParty_FK FOREIGN KEY (PersonId)
REFERENCES Party (PartyId)
);
CREATE TABLE Organization ( -- Represents the other subtype.
OrganizationId INT NOT NULL, -- To be CONSTRAINed as PRIMARY KEY and FOREIGN KEY simultaneously, enforcing a association cardinality of one-to-zero-or-one from Party to Organization.
Name CHAR(30) NOT NULL,
FoundingDate DATE NOT NULL,
Etcetera CHAR(30) NOT NULL,
--
CONSTRAINT Organization_PK PRIMARY KEY (OrganizationId),
CONSTRAINT Organization_AK UNIQUE (Name), -- ALTERNATE KEY.
CONSTRAINT OrganizationToParty_FK FOREIGN KEY (OrganizationId)
REFERENCES Party (PartyId)
);
CREATE TABLE UserProfile (
UserId INT NOT NULL, -- To be CONSTRAINed as PRIMARY KEY and FOREIGN KEY at the same time, enforcing an association cardinality of one-to-zero-or-one from Person to UserProfile.
UserName CHAR(30) NOT NULL,
CreatedDateTime TIMESTAMP NOT NULL,
Etcetera CHAR(30) NOT NULL,
--
CONSTRAINT UserProfile_PK PRIMARY KEY (UserId),
CONSTRAINT UserProfile_AK UNIQUE (Username),
CONSTRAINT UserProfileToPerson_FK FOREIGN KEY (UserId)
REFERENCES Person (PersonId)
);
CREATE TABLE Account (
AccountNumber INT NOT NULL,
OwnerPartyId INT NOT NULL, -- A role name assigned to PartyId in order to depict the meaning it carries in the context of an Account.
CreatedDateTime TIMESTAMP NOT NULL,
Etcetera CHAR(30) NOT NULL,
--
CONSTRAINT Account_PK PRIMARY KEY (AccountNumber),
CONSTRAINT AccountToParty_FK FOREIGN KEY (OwnerPartyId)
REFERENCES Party (PartyId)
);
CREATE TABLE Transfer (
TransferorAccountNumber INT NOT NULL, -- Role name assigned to AccountNumber.
TransfereeAccountNumber INT NOT NULL, -- Role name assigned to AccountNumber
TransferDateTime TIMESTAMP NOT NULL,
Amount INT NOT NULL, -- Retains the Amount in Cents, but there are other possibilities.
Etcetera CHAR(30) NOT NULL,
--
CONSTRAINT Transfer_PK PRIMARY KEY (TransferorAccountNumber, TransfereeAccountNumber, TransferDateTime), -- Composite PRIMARY KEY.
CONSTRAINT TransferToTransferor_FK FOREIGN KEY (TransferorAccountNumber)
REFERENCES Account (AccountNumber),
CONSTRAINT TransferToTransferee_FK FOREIGN KEY (TransfereeAccountNumber)
REFERENCES Account (AccountNumber),
CONSTRAINT AccountsAreDistinct_CK CHECK (TransferorAccountNumber <> TransfereeAccountNumber),
CONSTRAINT AmountIsValid_CK CHECK (Amount > 0)
);
Wie bereits erwähnt, müssen keine mehrdeutigen und problematischen NULL-Markierungen in den Spalten einer der Basistabellen beibehalten werden.
Wenn Sie wissen möchten, ob ein an einer bestimmten Übertragung beteiligtes Konto einer Organisation oder einer Person gehört , können Sie solche Informationen in einer einzelnen SELECT-Anweisung über z. B. die Spalten , die und die Spalten ableiten .Transfer.TrasnferorAccountNumber
Account.PartyId
Party.PartyTypeCode
Damit Sie sicherstellen können, dass eine Partei höchstens ein Konto besitzen kann (wie in den Kommentaren angegeben), sollten Sie eine EINZIGARTIGE Einschränkung für die Account.PartyId
Spalte festlegen . In realen Szenarien, z. B. in einer Bank, kann eine Person jedoch null, eins oder viele Konten besitzen. Daher schätze ich, dass eine Eins-zu-Null-oder-Eins-Zuordnung nicht realistisch erscheint.
Wie bereits erwähnt, soll der in dieser Antwort vorgeschlagene Ansatz als Referenz verwendet werden, die Sie selbst erweitern und anpassen können. Natürlich sollten Erweiterungen und Anpassungen auf konzeptioneller Ebene im logischen Modell berücksichtigt werden.
Ich habe die Deklaration dieser Struktur in (i) dieser Datenbank- Geige und in (ii) dieser SQL-Geige getestet , die beide unter PostgreSQL 9.6 ausgeführt werden (Sie haben ursprünglich das Tag dieses Datenbankverwaltungssystems angehängt).
Überlegungen zu Integrität und Konsistenz in Bezug auf die Tabellen Partei, Person und Organisation
Bei dem oben beschriebenen Layout muss sichergestellt werden, dass jede Zeile "Supertyp" jederzeit durch das entsprechende Gegenstück "Subtyp" ergänzt wird, und es muss wiederum sichergestellt werden, dass diese Zeile "Subtyp" mit dem im Supertyp "Diskriminator" enthaltenen Wert kompatibel ist " Säule.
Es wäre sehr praktisch und elegant, solche Umstände deklarativ durchzusetzen, aber leider hat keine der großen SQL-Plattformen die richtigen Mechanismen dafür bereitgestellt (soweit ich weiß). Daher ist es sehr praktisch, ACID TRANSACTIONS zu verwenden, damit diese Bedingungen in einer Datenbank immer sicher erfüllt werden.
Ähnliche Szenarien
Wenn Sie an anderen Geschäftsbereichen interessiert sind, in denen Supertyp-Subtyp-Strukturen entstehen, möchten Sie vielleicht meine Antworten auf sehen
Relevante Ressource
- Diese Stapelüberlauf-Posts decken sehr relevante Punkte in Bezug auf den Datentyp einer Spalte ab, die ein Währungsdatum enthält , wie
Transfer.Amount
in PostgreSQL.
Endnote
† Integration Definition für Informationsmodellierung ( IDEF1X ) ist eine sehr empfehlenswerte Datenmodellierungstechnik, die als etabliert wurde Standard im Dezember 1993 von den Vereinigten Staaten National Institute of Standards and Technology (NIST). Es basiert fest auf (a) einigen frühen theoretischen Arbeiten, die vom Urheber des relationalen Modells verfasst wurden, dh Dr. EF Codd ; zu (b) dervon Dr. PP Chen entwickelten Entity-Relationship-Sichtweise ; und auch auf (c) der Logical Database Design Technique, erstellt von Robert G. Brown.
Das Hinzufügen der Kontotabelle scheint das grundlegende Problem nicht zu ändern.
In TransferHistory können Sie TransferFrom und TransferFromType verwenden, wobei TransferFrom entweder ein Mitglied oder eine Organisations-ID ist und TransferFromType "M" oder "O" ist. Sie können hier überhaupt keine Fremdschlüssel verwenden und müssten die referenzielle Integrität "manuell" (z. B. mit Triggern) aufrechterhalten. Gleiches gilt für TransferTo.
Eine Abfrage würde ungefähr so aussehen (bei Bedarf durch tatsächliche Felder ersetzen):
Oder Sie haben 4 Felder
TransferFromMember
,TransferFrom Org
, TransferToMemberand
TransferToOrg`, alle Fremdschlüssel und Nutzungsmöglichkeiten, um sicherzustellen , nur ein Von- und ein zu setzen.Eine Abfrage würde ungefähr so aussehen (bei Bedarf durch tatsächliche Felder ersetzen):
quelle