Wenn ich Ihre Spezifikationen richtig verstehe, beinhaltet Ihr Szenario - unter anderen wichtigen Aspekten - eine Supertyp-Subtyp- Struktur.
Ich werde im Folgenden beispielhaft erläutern, wie (1) es auf der konzeptionellen Abstraktionsebene modelliert und anschließend (2) in einem DDL-Design auf logischer Ebene dargestellt wird .
Geschäftsregeln
Die folgenden konzeptionellen Formulierungen gehören zu den wichtigsten Regeln in Ihrem Geschäftskontext:
- Eine Wiedergabeliste gehört zu einem bestimmten Zeitpunkt entweder genau einer Gruppe oder genau einem Benutzer
- Eine Wiedergabeliste kann zu unterschiedlichen Zeitpunkten einer oder mehreren Gruppen oder Benutzern gehören
- Ein Benutzer besitzt null, eins oder viele Wiedergabelisten
- Eine Gruppe besitzt null, eins oder viele Wiedergabelisten
- Eine Gruppe besteht aus einem bis vielen Mitgliedern (die Benutzer sein müssen ).
- Ein Benutzer kann Mitglied von Null-Eins-oder-Viele- Gruppen sein .
- Eine Gruppe besteht aus einem bis vielen Mitgliedern (die Benutzer sein müssen ).
Da die Assoziationen oder Beziehungen (a) zwischen Benutzer und Wiedergabeliste und (b) zwischen Gruppe und Wiedergabeliste ziemlich ähnlich sind, zeigt diese Tatsache, dass Benutzer und Gruppe sich gegenseitig ausschließende Entitätsuntertypen von Partei 1 sind , die wiederum ihren Entitäts-Supertyp - Supertyp - sind. Subtyp-Cluster sind klassische Datenstrukturen, die in konzeptionellen Schemata sehr unterschiedlicher Art entstehen. Auf diese Weise können zwei neue Regeln geltend gemacht werden:
- Eine Party wird nach genau einem PartyType kategorisiert
- Eine Partei ist entweder eine Gruppe oder ein Benutzer
Und vier der vorherigen Regeln müssen als nur drei umformuliert werden:
- Eine Wiedergabeliste gehört zu einem bestimmten Zeitpunkt genau einer Partei
- Eine Wiedergabeliste kann zu unterschiedlichen Zeitpunkten im Besitz von einer bis mehreren Parteien sein
- Eine Partei besitzt null, eins oder viele Wiedergabelisten
Expository IDEF1X-Diagramm
Das in Abbildung 1 gezeigte IDEF1X 2- Diagramm konsolidiert alle oben genannten Geschäftsregeln zusammen mit anderen, die relevant erscheinen:
Wie gezeigt, werden Gruppe und Benutzer als Untertypen dargestellt, die durch die jeweiligen Linien und das exklusive Symbol mit Party , dem Supertyp, verbunden sind.
Die Party.PartyTypeCode- Eigenschaft steht für den Subtyp- Diskriminator , dh sie gibt an, welche Art von Subtyp-Instanz ein bestimmtes Supertyp-Vorkommen ergänzen muss.
Außerdem ist Party über die OwnerId- Eigenschaft mit der Wiedergabeliste verbunden, die als AUSLÄNDISCHER SCHLÜSSEL dargestellt wird, der auf Party.PartyId verweist . Auf diese Weise verknüpft die Partei (a) die Wiedergabeliste mit (b) der Gruppe und (c) dem Benutzer .
Da eine bestimmte Party- Instanz entweder eine Gruppe oder ein Benutzer ist , kann eine bestimmte Wiedergabeliste mit höchstens einem Subtyp-Vorkommen verknüpft werden.
Illustratives Layout auf logischer Ebene
Das zuvor erläuterte IDEF1X-Diagramm diente mir als Plattform zum Erstellen der folgenden logischen SQL-DDL-Anordnung (und ich habe Anmerkungen als Kommentare bereitgestellt, in denen mehrere Punkte von besonderer Relevanz hervorgehoben wurden - z. B. die Einschränkungsdeklarationen -):
-- You should determine which are the most fitting
-- data types and sizes for all your table columns
-- depending on your business context characteristics.
-- Also, you should make accurate tests to define the
-- most convenient INDEX strategies based on the exact
-- data manipulation tendencies of your business domain.
-- As one would expect, you are free to utilize
-- your preferred (or required) naming conventions.
CREATE TABLE PartyType ( -- Represents an independent entity type.
PartyTypeCode CHAR(1) NOT NULL,
Name CHAR(30) NOT NULL,
--
CONSTRAINT PartyType_PK PRIMARY KEY (PartyTypeCode),
CONSTRAINT PartyType_AK UNIQUE (Name)
);
CREATE TABLE Party ( -- Stands for the supertype.
PartyId INT NOT NULL,
PartyTypeCode CHAR(1) NOT NULL, -- Symbolizes the discriminator.
CreatedDateTime TIMESTAMP NOT NULL,
--
CONSTRAINT Party_PK PRIMARY KEY (PartyId),
CONSTRAINT PartyToPartyType_FK FOREIGN KEY (PartyTypeCode)
REFERENCES PartyType (PartyTypeCode)
);
CREATE TABLE UserProfile ( -- Denotes one of the subtypes.
UserId INT NOT NULL, -- To be constrained as both (a) the PRIMARY KEY and (b) a FOREIGN KEY.
UserName CHAR(30) NOT NULL,
FirstName CHAR(30) NOT NULL,
LastName CHAR(30) NOT NULL,
GenderCode CHAR(3) NOT NULL,
BirthDate DATE NOT NULL,
--
CONSTRAINT UserProfile_PK PRIMARY KEY (UserId),
CONSTRAINT UserProfile_AK1 UNIQUE ( -- Multi-column ALTERNATE KEY.
FirstName,
LastName,
GenderCode,
BirthDate
),
CONSTRAINT UserProfile_AK2 UNIQUE (UserName), -- Single-column ALTERNATE KEY.
CONSTRAINT UserProfileToParty_FK FOREIGN KEY (UserId)
REFERENCES Party (PartyId)
);
CREATE TABLE MyGroup ( -- Represents the other subtype.
GroupId INT NOT NULL, -- To be constrained as both (a) the PRIMARY KEY and (b) a FOREIGN KEY.
Title CHAR(30) NOT NULL,
--
CONSTRAINT Group_PK PRIMARY KEY (GroupId),
CONSTRAINT Group_AK UNIQUE (Title), -- ALTERNATE KEY.
CONSTRAINT GroupToParty_FK FOREIGN KEY (GroupId)
REFERENCES Party (PartyId)
);
CREATE TABLE Playlist ( -- Stands for an independent entity type.
PlaylistId INT NOT NULL,
OwnerId INT NOT NULL,
Title CHAR(30) NOT NULL,
CreatedDateTime TIMESTAMP NOT NULL,
--
CONSTRAINT Playlist_PK PRIMARY KEY (PlaylistId),
CONSTRAINT Playlist_AK UNIQUE (Title), -- ALTERNATE KEY.
CONSTRAINT PartyToParty_FK FOREIGN KEY (OwnerId) -- Establishes the relationship with (a) the supertype and (b) through the subtype with (c) the subtypes.
REFERENCES Party (PartyId)
);
CREATE TABLE GroupMember ( -- Denotes an associative entity type.
MemberId INT NOT NULL,
GroupId INT NOT NULL,
IsOwner BOOLEAN NOT NULL,
JoinedDateTime TIMESTAMP NOT NULL,
--
CONSTRAINT GroupMember_PK PRIMARY KEY (MemberId, GroupId), -- Composite PRIMARY KEY.
CONSTRAINT GroupMemberToUserProfile_FK FOREIGN KEY (MemberId)
REFERENCES UserProfile (UserId),
CONSTRAINT GroupMemberToMyGroup_FK FOREIGN KEY (GroupId)
REFERENCES MyGroup (GroupId)
);
Natürlich können Sie eine oder mehrere Anpassungen vornehmen, damit alle Merkmale Ihres Geschäftskontexts mit der erforderlichen Genauigkeit in der tatsächlichen Datenbank dargestellt werden.
Hinweis : Ich habe das obige logische Layout auf dieser db <> -Fiedel und auch auf dieser SQL-Geige getestet , die beide unter PostgreSQL 9.6 "ausgeführt" werden, damit Sie sie "in Aktion" sehen können.
Die Schnecken
Wie Sie sehen können, habe ich weder in die DDL-Deklarationen Group.Slug
noch Playlist.Slug
als Spalten aufgenommen. Dies liegt daran, dass in Übereinstimmung mit Ihrer folgenden Erklärung
Dies slug
sind eindeutige Versionen der jeweiligen Entität in Kleinbuchstaben und mit Bindestrich title
. Zum Beispiel würde ein group
mit title
der slug
'Testgruppe' die 'Testgruppe' haben. Duplikate werden mit inkrementellen Ganzzahlen angehängt. Dies würde sich jederzeit title
ändern. Ich glaube, das bedeutet, dass sie keine großartigen Primärschlüssel machen würden? Ja, slugs
und usernames
sind in ihren jeweiligen Tabellen eindeutig.
man kann daraus schließen, dass ihre Werte ableitbar sind (dh sie müssen in Bezug auf die entsprechenden Group.Title
und Playlist.Title
Werte berechnet oder berechnet werden, manchmal in Verbindung mit - ich nehme an, eine Art von systemgenerierten INTEGERs), daher würde ich diese Spalten nicht deklarieren in einer der Basistabellen als würden sie neue Unregelmäßigkeiten einzuführen.
Im Gegensatz dazu würde ich das produzieren Slugs
Vielleicht kann in einer Ansicht , die (a) die Ableitung solcher Werte in virtuellen Spalten enthält und (b) direkt in weiteren SELECT-Operationen verwendet werden kann - das Anhängen des INTEGER-Teils könnte beispielsweise durch Kombinieren des Werts von (1) erhalten werden. die Playlist.OwnerId
mit (2) den Zwischenbindestrichen und (3) dem Wert der Playlist.Title
;
oder aufgrund des Anwendungsprogrammcodes den zuvor beschriebenen Ansatz (möglicherweise prozedural) nachahmen, sobald die relevanten Datensätze abgerufen und für die Interpretation durch den Endbenutzer formatiert wurden.
Auf diese Weise würde jede dieser beiden Methoden den Mechanismus der "Aktualisierungssynchronisation" vermeiden, der eingerichtet werden sollte, wenn die Slugs
in Spalten von Basistabellen beibehalten werden.
Überlegungen zu Integrität und Konsistenz
Es ist wichtig zu erwähnen, dass (i) jede Party
Zeile jederzeit durch (ii) das jeweilige Gegenstück in genau einer der Tabellen für die Untertypen ergänzt werden muss, die (iii) dem in der Party.PartyTypeCode
Spalte enthaltenen Wert „entsprechen“ müssen - den Diskriminator bezeichnen -.
Es wäre durchaus vorteilhaft, diese Art von Situation deklarativ durchzusetzen , aber keines der großen SQL-Datenbankverwaltungssysteme (einschließlich Postgres) hat die erforderlichen Instrumente bereitgestellt , um so vorzugehen. Daher ist das Schreiben von Verfahrenscode in ACID TRANSACTIONS bislang die beste Option, um sicherzustellen, dass die zuvor beschriebenen Umstände in Ihrer Datenbank immer erfüllt sind . Eine andere Möglichkeit wäre, auf TRIGGERS zurückzugreifen, aber sie neigen dazu, die Dinge sozusagen unordentlich zu machen.
Vergleichbare Fälle
Wenn Sie einige Analogien feststellen möchten, könnten Sie sich meine Antworten auf die (neueren) Fragen mit dem Titel ansehen
da werden vergleichbare szenarien diskutiert.
Endnoten
1 - Partei ist ein Begriff in rechtlichen Zusammenhängen verwendet werdenwenn entweder einem Bezug einzelne oder eine Gruppe von Personen , die eine einzelne Einheit zusammensetzen , so dass diesegeeignethatdie Konzepte der repräsentieren Benutzer und Gruppen in Bezug auf das Geschäftsumfeld in Frage.
2 Integration Definition für Information Modeling ( 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 der frühen theoretischen Arbeiten, die vom alleinigen Urheber des relationalen Modells verfasst wurden , dh Dr. EF Codd ; zu (b) dervon Dr. PP Chen entwickelten Entity-Relationship-Sicht ; und auch auf (c) der Logical Database Design Technique, erstellt von Robert G. Brown.