Entsprechend Ihrer Beschreibung des betrachteten Geschäftsumfelds gibt es eine Supertyp-Subtyp- Struktur, die Item - den Supertyp - und jede seiner Kategorien , dh Auto , Boot, umfasst und Flugzeug (zusammen mit zwei weiteren, die nicht bekannt gegeben wurden). die Untertypen -.
Ich werde im Folgenden detailliert auf die Methode eingehen, mit der ich ein solches Szenario verwalten würde.
Geschäftsregeln
Um mit der Abgrenzung des relevanten konzeptionellen Schemas zu beginnen, können einige der wichtigsten bisher festgelegten Geschäftsregeln (Beschränkung der Analyse auf die drei offenbarten Kategorien , um die Dinge so kurz wie möglich zu halten) wie folgt formuliert werden:
- Ein Benutzer besitzt null, eins oder viele Gegenstände
- Ein Artikel gehört zu einem bestimmten Zeitpunkt genau einem Benutzer
- Ein Artikel kann zu unterschiedlichen Zeitpunkten Eigentum von einem bis vielen Benutzern sein
- Ein Artikel wird nach genau einer Kategorie klassifiziert
- Ein Gegenstand ist zu jeder Zeit
- entweder ein Auto
- oder ein Boot
- oder ein Flugzeug
Illustratives IDEF1X-Diagramm
Abbildung 1 zeigt ein IDEF1X 1- Diagramm, das ich erstellt habe, um die vorherigen Formulierungen zusammen mit anderen Geschäftsregeln zu gruppieren, die relevant erscheinen:
Supertyp
Einerseits zeigt Item , der Supertyp, die Eigenschaften † oder Attribute an, die allen Kategorien gemeinsam sind , d. H.
- CategoryCode - angegeben als FOREIGN KEY (FK), der auf Category.CategoryCode verweist und als Subtyp- Diskriminator fungiert , dh die genaue Kategorie des Subtyps angibt, mit dem ein bestimmtes Element verbunden werden muss -,
- OwnerId - wird als FK unterschieden, das auf User.UserId verweist , aber ich habe ihm einen Rollennamen 2 zugewiesen , um seine besonderen Auswirkungen genauer wiederzugeben -.
- Foo ,
- Bar ,
- Baz und
- CreatedDateTime .
Untertypen
Auf der anderen Seite die Eigenschaften ‡ , die sich auf jede bestimmte Kategorie beziehen , dh
- Qux und Corge ;
- Grault , Garply und Plugh ;
- Xyzzy , Thud , Wibble und Flob ;
werden im entsprechenden Subtypfeld angezeigt.
Kennungen
Dann hat der Item.ItemId PRIMARY KEY (PK) 3 zu den Untertypen mit unterschiedlichen Rollennamen migriert , d. H.
- CarId ,
- BoatId und
- FlugzeugId .
Sich gegenseitig ausschließende Assoziationen
Wie dargestellt, besteht eine Assoziation oder Beziehung der Kardinalität eins zu eins (1: 1) zwischen (a) jedem Auftreten eines Supertyps und (b) seiner komplementären Subtypinstanz.
Das exklusive Subtypsymbol zeigt die Tatsache an, dass sich die Subtypen gegenseitig ausschließen, dh ein konkretes Vorkommen von Gegenständen kann nur durch eine einzelne Subtypinstanz ergänzt werden: entweder ein Auto oder ein Flugzeug oder ein Boot (niemals durch zwei oder mehr).
† , ‡ Ich habe klassische Platzhalternamen verwendet, um einige der Entitätstyp-Eigenschaften zu berechtigen, da ihre tatsächlichen Bezeichnungen in der Frage nicht angegeben wurden.
Layout auf logischer Ebene des Expositorys
Um ein logisches Expository-Design zu diskutieren, habe ich die folgenden SQL-DDL-Anweisungen basierend auf dem oben angezeigten und beschriebenen IDEF1X-Diagramm abgeleitet:
-- 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 context.
-- As one would expect, you are free to utilize
-- your preferred (or required) naming conventions.
CREATE TABLE UserProfile (
UserId INT NOT NULL,
FirstName CHAR(30) NOT NULL,
LastName CHAR(30) NOT NULL,
BirthDate DATE NOT NULL,
GenderCode CHAR(3) NOT NULL,
Username CHAR(20) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT UserProfile_PK PRIMARY KEY (UserId),
CONSTRAINT UserProfile_AK1 UNIQUE ( -- Composite ALTERNATE KEY.
FirstName,
LastName,
GenderCode,
BirthDate
),
CONSTRAINT UserProfile_AK2 UNIQUE (Username) -- ALTERNATE KEY.
);
CREATE TABLE Category (
CategoryCode CHAR(1) NOT NULL, -- Meant to contain meaningful, short and stable values, e.g.; 'C' for 'Car'; 'B' for 'Boat'; 'P' for 'Plane'.
Name CHAR(30) NOT NULL,
--
CONSTRAINT Category_PK PRIMARY KEY (CategoryCode),
CONSTRAINT Category_AK UNIQUE (Name) -- ALTERNATE KEY.
);
CREATE TABLE Item ( -- Stands for the supertype.
ItemId INT NOT NULL,
OwnerId INT NOT NULL,
CategoryCode CHAR(1) NOT NULL, -- Denotes the subtype discriminator.
Foo CHAR(30) NOT NULL,
Bar CHAR(30) NOT NULL,
Baz CHAR(30) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Item_PK PRIMARY KEY (ItemId),
CONSTRAINT Item_to_Category_FK FOREIGN KEY (CategoryCode)
REFERENCES Category (CategoryCode),
CONSTRAINT Item_to_User_FK FOREIGN KEY (OwnerId)
REFERENCES UserProfile (UserId)
);
CREATE TABLE Car ( -- Represents one of the subtypes.
CarId INT NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
Qux CHAR(30) NOT NULL,
Corge CHAR(30) NOT NULL,
--
CONSTRAINT Car_PK PRIMARY KEY (CarId),
CONSTRAINT Car_to_Item_FK FOREIGN KEY (CarId)
REFERENCES Item (ItemId)
);
CREATE TABLE Boat ( -- Stands for one of the subtypes.
BoatId INT NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
Grault CHAR(30) NOT NULL,
Garply CHAR(30) NOT NULL,
Plugh CHAR(30) NOT NULL,
--
CONSTRAINT Boat_PK PRIMARY KEY (BoatId),
CONSTRAINT Boat_to_Item_FK FOREIGN KEY (BoatId)
REFERENCES Item (ItemId)
);
CREATE TABLE Plane ( -- Denotes one of the subtypes.
PlaneId INT NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
Xyzzy CHAR(30) NOT NULL,
Thud CHAR(30) NOT NULL,
Wibble CHAR(30) NOT NULL,
Flob CHAR(30) NOT NULL,
--
CONSTRAINT Plane_PK PRIMARY KEY (PlaneId),
CONSTRAINT Plane_to_Item_PK FOREIGN KEY (PlaneId)
REFERENCES Item (ItemId)
);
Wie gezeigt, ist der superentity Typ und jeder der Sub - Entität Typen durch die entsprechende dargestellte Basistabelle.
Die Spalten CarId
, BoatId
und PlaneId
, eingeschränkt , wie die PKs der entsprechenden Tabellen, Hilfe in der die konzeptionellen Ebene Eins-zu-Eins - Zuordnung haft FK Constraints § dieses Punkt zu der ItemId
Spalte, die als PK der gezwungen ist Item
Tabelle. Dies bedeutet, dass in einem tatsächlichen „Paar“ sowohl die Supertyp- als auch die Subtypzeile durch denselben PK-Wert identifiziert werden. Daher ist es mehr als angebracht, dies zu erwähnen
- (a) Das Anhängen einer zusätzlichen Spalte zum Halten systemgesteuerter Ersatzwerte ‖ an (b) die Tabellen, die für die Untertypen stehen, ist (c) völlig überflüssig .
§ Um Probleme und Fehler in Bezug auf (insbesondere AUSLÄNDISCHE) KEY-Einschränkungsdefinitionen zu vermeiden - Situation, auf die Sie in Kommentaren Bezug genommen haben -, ist es sehr wichtig, die Existenzabhängigkeit zu berücksichtigen, die zwischen den verschiedenen vorliegenden Tabellen auftritt , wie in dargestellt Die Deklarationsreihenfolge der Tabellen in der Expository-DDL-Struktur, die ich auch in dieser SQL-Geige angegeben habe.
‖ Anhängen einer zusätzlichen Spalte mit der Eigenschaft AUTO_INCREMENT an eine Tabelle einer auf MySQL basierenden Datenbank.
Überlegungen zu Integrität und Konsistenz
Es ist wichtig darauf hinzuweisen, dass Sie in Ihrem Geschäftsumfeld (1) sicherstellen müssen, dass jede Zeile "Supertyp" jederzeit durch das entsprechende Gegenstück "Subtyp" ergänzt wird, und (2) dies wiederum garantieren Die Zeile "Subtyp" ist mit dem Wert kompatibel, der in der Spalte "Diskriminator" der Zeile "Supertyp" enthalten ist.
Es wäre sehr elegant, solche Umstände deklarativ durchzusetzen , aber leider hat meines Wissens keine der großen SQL-Plattformen die richtigen Mechanismen dafür bereitgestellt. Daher wird in ACID TRANSACTIONS auf Verfahrenscode zurückgegriffen ist es sehr praktisch, , damit diese Bedingungen in Ihrer Datenbank immer erfüllt sind. Eine andere Möglichkeit wäre der Einsatz von TRIGGERS, aber sie neigen dazu, die Dinge sozusagen unordentlich zu machen.
Nützliche Ansichten deklarieren
Ein logisches Design wie das mit dem oben erläuterte, wäre es sehr praktisch sein , eine oder mehr Ansichten zu erstellen, dh abgeleitete Tabellen , die Spalten enthalten, die zwei oder mehr der relevanten gehören Basistabellen. Auf diese Weise können Sie beispielsweise direkt AUS diesen Ansichten AUSWÄHLEN, ohne jedes Mal alle JOINs schreiben zu müssen, wenn Sie „kombinierte“ Informationen abrufen müssen.
Beispieldaten
Nehmen wir in diesem Zusammenhang an, dass die Basistabellen mit den unten gezeigten Beispieldaten „gefüllt“ sind:
--
INSERT INTO UserProfile
(UserId, FirstName, LastName, BirthDate, GenderCode, Username, CreatedDateTime)
VALUES
(1, 'Edgar', 'Codd', '1923-08-19', 'M', 'ted.codd', CURDATE()),
(2, 'Michelangelo', 'Buonarroti', '1475-03-06', 'M', 'michelangelo', CURDATE()),
(3, 'Diego', 'Velázquez', '1599-06-06', 'M', 'd.velazquez', CURDATE());
INSERT INTO Category
(CategoryCode, Name)
VALUES
('C', 'Car'), ('B', 'Boat'), ('P', 'Plane');
-- 1. ‘Full’ Car INSERTion
-- 1.1
INSERT INTO Item
(ItemId, OwnerId, CategoryCode, Foo, Bar, Baz, CreatedDateTime)
VALUES
(1, 1, 'C', 'This datum', 'That datum', 'Other datum', CURDATE());
-- 1.2
INSERT INTO Car
(CarId, Qux, Corge)
VALUES
(1, 'Fantastic Car', 'Powerful engine pre-update!');
-- 2. ‘Full’ Boat INSERTion
-- 2.1
INSERT INTO Item
(ItemId, OwnerId, CategoryCode, Foo, Bar, Baz, CreatedDateTime)
VALUES
(2, 2, 'B', 'This datum', 'That datum', 'Other datum', CURDATE());
-- 2.2
INSERT INTO Boat
(BoatId, Grault, Garply, Plugh)
VALUES
(2, 'Excellent boat', 'Use it to sail', 'Everyday!');
-- 3 ‘Full’ Plane INSERTion
-- 3.1
INSERT INTO Item
(ItemId, OwnerId, CategoryCode, Foo, Bar, Baz, CreatedDateTime)
VALUES
(3, 3, 'P', 'This datum', 'That datum', 'Other datum', CURDATE());
-- 3.2
INSERT INTO Plane
(PlaneId, Xyzzy, Thud, Wibble, Flob)
VALUES
(3, 'Extraordinary plane', 'Traverses the sky', 'Free', 'Like a bird!');
--
Dann wird eine vorteilhafte Ansicht ist eine , die Raffungen Spalten aus Item
, Car
und UserProfile
:
--
CREATE VIEW CarAndOwner AS
SELECT C.CarId,
I.Foo,
I.Bar,
I.Baz,
C.Qux,
C.Corge,
U.FirstName AS OwnerFirstName,
U.LastName AS OwnerLastName
FROM Item I
JOIN Car C
ON C.CarId = I.ItemId
JOIN UserProfile U
ON U.UserId = I.OwnerId;
--
Natürlich kann ein ähnlicher Ansatz verfolgt werden, so dass Sie auch die "vollständigen" Boat
und Plane
Informationen direkt aus einer einzigen Tabelle auswählen können (in diesen Fällen einer abgeleiteten) auswählen können.
Danach -wenn Sie nicht über das Vorhandensein von NULL Marken in Folge Sets- mit folgenden VIEW Definition etwas dagegen, können Sie, zB „collect“ Spalten aus den Tabellen Item
, Car
, Boat
, Plane
und UserProfile
:
--
CREATE VIEW FullItemAndOwner AS
SELECT I.ItemId,
I.Foo, -- Common to all Categories.
I.Bar, -- Common to all Categories.
I.Baz, -- Common to all Categories.
IC.Name AS Category,
C.Qux, -- Applies to Cars only.
C.Corge, -- Applies to Cars only.
--
B.Grault, -- Applies to Boats only.
B.Garply, -- Applies to Boats only.
B.Plugh, -- Applies to Boats only.
--
P.Xyzzy, -- Applies to Planes only.
P.Thud, -- Applies to Planes only.
P.Wibble, -- Applies to Planes only.
P.Flob, -- Applies to Planes only.
U.FirstName AS OwnerFirstName,
U.LastName AS OwnerLastName
FROM Item I
JOIN Category IC
ON I.CategoryCode = IC.CategoryCode
LEFT JOIN Car C
ON C.CarId = I.ItemId
LEFT JOIN Boat B
ON B.BoatId = I.ItemId
LEFT JOIN Plane P
ON P.PlaneId = I.ItemId
JOIN UserProfile U
ON U.UserId = I.OwnerId;
--
Der Code der hier gezeigten Ansichten dient nur zur Veranschaulichung. Natürlich können einige Testübungen und Änderungen dazu beitragen, die (physische) Ausführung der vorliegenden Abfragen zu beschleunigen. Darüber hinaus müssen Sie möglicherweise Spalten entfernen oder zu diesen Ansichten hinzufügen, je nach den geschäftlichen Anforderungen.
Die Beispieldaten und alle Ansichtsdefinitionen sind in diese SQL-Geige integriert, damit sie „in Aktion“ beobachtet werden können.
Datenmanipulation: Code und Spaltenaliasnamen von Anwendungsprogrammen
Die Verwendung von Anwendungsprogrammcode (wenn Sie dies mit "serverseitigem spezifischem Code" meinen) und Spaltenaliasnamen sind weitere wichtige Punkte, die Sie in den nächsten Kommentaren angesprochen haben:
Ich habe es geschafft, [ein JOIN] -Problem mit serverseitigem Code zu umgehen, aber ich möchte wirklich nicht, dass das Hinzufügen von Aliasen zu allen Spalten "stressig" ist.
Sehr gut erklärt, vielen Dank. Wie ich jedoch vermutet habe, muss ich die Ergebnismenge beim Auflisten aller Daten aufgrund der Ähnlichkeiten mit einigen Spalten manipulieren, da ich nicht mehrere Aliase verwenden möchte, um die Anweisung sauberer zu halten.
Es ist angebracht anzugeben, dass die Verwendung von Anwendungsprogrammcode eine sehr geeignete Ressource für die Darstellung (oder grafische) Präsentationsfunktionen von Ergebnismengen ist. Die Vermeidung zeilenweiser Datenabrufe ist jedoch von größter Bedeutung, um Probleme mit der Ausführungsgeschwindigkeit zu vermeiden. Das Ziel sollte darin bestehen, die relevanten Datensätze mithilfe der robusten Datenmanipulationsinstrumente, die von der (genau) festgelegten Engine der SQL-Plattform bereitgestellt werden, vollständig abzurufen, damit Sie das Verhalten Ihres Systems optimieren können.
Darüber hinaus mag die Verwendung von Aliasen zum Umbenennen einer oder mehrerer Spalten innerhalb eines bestimmten Bereichs stressig erscheinen, aber ich persönlich sehe diese Ressource als ein sehr leistungsfähiges Werkzeug, das hilft, (i) die Bedeutung und Absicht zu kontextualisieren und (ii) zu disambiguieren zugeschriebene zu Säulen; Daher ist dies ein Aspekt, über den im Hinblick auf die Manipulation der interessierenden Daten gründlich nachgedacht werden sollte.
Ähnliche Szenarien
Sie können genauso gut Hilfe bei dieser Reihe von Beiträgen und dieser Gruppe von Beiträgen finden , die meine Meinung zu zwei anderen Fällen enthalten, die Supertyp-Subtyp-Assoziationen mit sich gegenseitig ausschließenden Subtypen enthalten.
Ich habe auch eine Lösung für eine Geschäftsumgebung vorgeschlagen, die einen Supertyp-Subtyp-Cluster umfasst, bei dem sich die Subtypen in dieser (neueren) Antwort nicht gegenseitig ausschließen .
Endnoten
1 Integration Definition für Information Modeling ( IDEF1X ) ist eine sehr empfehlenswerte Datenmodellierungstechnik, die als etabliert wurde Standard im Dezember 1993 von der US National Institute of Standards and Technology (NIST). Es basiert fest auf (a) einigen 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.
2 In IDEF1X ein Rollenname ist eine unterscheidende Markierung an einer FKEigenschaft zugewiesen (oder Attribut), um die Bedeutung auszudrückendass es im Rahmen seiner jeweiligen Entitätstyp hält.
3 Der IDEF1X-Standard definiert die Schlüsselmigration als „Modellierungsprozess zum Platzieren des Primärschlüssels einer übergeordneten oder generischen Entität in ihrer untergeordneten oder Kategorie-Entität als Fremdschlüssel“.
Item
Tabelle eineCategoryCode
Spalte. Wie im Abschnitt "Überlegungen zu Integrität und Konsistenz" erwähnt:CategoryColumn
der Tabellen, die für die Untertypen stehen (mit allen Auswirkungen auf die logischen [z. B. Modifikationsanomalien] und physischen Abstraktionsebenen [z. B. zusätzliche Indizes, größere Strukturen usw.]).Nennen wir die Haupttabelle Produkte. Hier werden die gemeinsam genutzten Attribute gehostet. Dann nehmen wir an, wir haben einen Autotisch, einen Flugzeugtisch und einen Bootstisch. Diese drei Tabellen hätten einen ProductID-Schlüssel mit einer FK-Einschränkung in der ID-Zeile der Product-Tabelle. Wenn Sie sie alle wollen - schließen Sie sich ihnen an. Wenn Sie nur die Autos wollen, verbinden Sie links Autos mit Produkten (oder rechts verbinden Sie Produkte und Autos, aber ich bevorzuge immer linksseitige Verbindungen).
Dies wird als hiearchisches Datenmodell bezeichnet. Bei einer geringen Anzahl von Untertabellen kann dies in einer langen Tabelle (Millionen von Produkten) sinnvoll sein.
quelle