Wenn man das Szenario analysiert, in dem Merkmale des Themas dargestellt werden, die als Zeitdatenbanken bezeichnet werden , kann man aus konzeptioneller Sicht Folgendes feststellen: (a) eine „aktuelle“ Blog-Story-Version und (b) eine „vergangene“ Blog-Story-Version , wenn auch sehr ähnlich sind Entitäten verschiedener Arten.
Darüber hinaus müssen auf der logischen Abstraktionsebene Fakten (dargestellt durch Zeilen) unterschiedlicher Art in unterschiedlichen Tabellen aufbewahrt werden. Im betrachteten Fall unterscheiden sich (i) Fakten über „aktuelle“ Versionen von (ii) Fakten über „frühere“ Versionen , selbst wenn sie sehr ähnlich sind .
Daher empfehle ich, die Situation anhand von zwei Tabellen zu verwalten:
eine, die ausschließlich für die „aktuellen“ oder „gegenwärtigen“ Versionen der Blog-Geschichten bestimmt ist , und
eine, die für alle "vorherigen" oder "früheren" Versionen getrennt, aber auch mit der anderen verbunden ist ;
jeweils mit (1) einer geringfügig unterschiedlichen Anzahl von Spalten und (2) einer unterschiedlichen Gruppe von Einschränkungen.
Zurück zur konzeptionellen Ebene, denke ich, dass in Ihrer Geschäftsumgebung Autor und Herausgeber Begriffe sind, die als Rollen definiert werden können, die von einem Benutzer gespielt werden können. Diese wichtigen Aspekte hängen von der Datenableitung ab (über Manipulationsoperationen auf logischer Ebene). und Interpretation (durchgeführt von den Blog Stories- Lesern und -Schreibern auf der externen Ebene des computergestützten Informationssystems mit Hilfe eines oder mehrerer Anwendungsprogramme).
Ich werde alle diese Faktoren und andere relevante Punkte wie folgt detaillieren.
Geschäftsregeln
Nach meinem Verständnis Ihrer Anforderungen sind die folgenden Geschäftsregelformulierungen (zusammengestellt in Bezug auf die relevanten Entitätstypen und ihre Arten von Wechselbeziehungen) besonders hilfreich, um das entsprechende konzeptionelle Schema zu erstellen:
- Ein Benutzer schreibt null-eins-oder-viele BlogStories
- Eine BlogStory enthält null-eins-oder-viele BlogStoryVersions
- Ein Benutzer hat null-eins-oder-viele BlogStoryVersions geschrieben
Expository IDEF1X Diagramm
Folglich, um meinen Vorschlag auf Grund einer graphischen Einrichtung zu auslegen, hat ich eine Probe IDEF1X erstellt ein Diagramm , das von den Geschäftsregeln formuliert und anderen Merkmalen abgeleitet ist , die relevant erscheinen. In Abbildung 1 ist Folgendes dargestellt :
Warum werden BlogStory und BlogStoryVersion als zwei verschiedene Entitätstypen konzipiert?
Weil:
Eine BlogStoryVersion- Instanz (dh eine "vergangene") enthält immer einen Wert für eine UpdatedDateTime- Eigenschaft, während eine BlogStory-Instanz (dh eine "aktuelle") diesen Wert niemals enthält.
Außerdem werden die Entitäten dieser Typen durch die Werte von zwei unterschiedlichen Eigenschaftssätzen eindeutig identifiziert: BlogStoryNumber (im Fall der BlogStory- Vorkommen) und BlogStoryNumber plus CreatedDateTime (im Fall der BlogStoryVersion- Instanzen).
eine Definition Integration 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 auf dem frühen theoretischen Material, das vom alleinigen Urheber des relationalen Modells verfasst wurde , dh Dr. EF Codd ; zur Entity-Relationship- Sicht der Daten, entwickelt von Dr. PP Chen ; und auch auf der Logical Database Design Technique, erstellt von Robert G. Brown.
Beispielhaftes logisches SQL-DDL-Layout
Dann habe ich auf der Grundlage der zuvor vorgestellten konzeptionellen Analyse den folgenden Entwurf auf logischer Ebene deklariert:
-- 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 at the physical level.
-- As one would expect, you are free to make use of
-- your preferred (or required) naming conventions.
CREATE TABLE UserProfile (
UserId INT NOT NULL,
FirstName CHAR(30) NOT NULL,
LastName CHAR(30) NOT NULL,
BirthDate DATETIME 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,
BirthDate,
GenderCode
),
CONSTRAINT UserProfile_AK2 UNIQUE (UserName) -- ALTERNATE KEY.
);
CREATE TABLE BlogStory (
BlogStoryNumber INT NOT NULL,
Title CHAR(60) NOT NULL,
Content TEXT NOT NULL,
CoverImageName CHAR(30) NOT NULL,
IsActive BIT(1) NOT NULL,
AuthorId INT NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT BlogStory_PK PRIMARY KEY (BlogStoryNumber),
CONSTRAINT BlogStory_AK UNIQUE (Title), -- ALTERNATE KEY.
CONSTRAINT BlogStoryToUserProfile_FK FOREIGN KEY (AuthorId)
REFERENCES UserProfile (UserId)
);
CREATE TABLE BlogStoryVersion (
BlogStoryNumber INT NOT NULL,
CreatedDateTime DATETIME NOT NULL,
Title CHAR(60) NOT NULL,
Content TEXT NOT NULL,
CoverImageName CHAR(30) NOT NULL,
IsActive BIT(1) NOT NULL,
AuthorId INT NOT NULL,
UpdatedDateTime DATETIME NOT NULL,
--
CONSTRAINT BlogStoryVersion_PK PRIMARY KEY (BlogStoryNumber, CreatedDateTime), -- Composite PK.
CONSTRAINT BlogStoryVersionToBlogStory_FK FOREIGN KEY (BlogStoryNumber)
REFERENCES BlogStory (BlogStoryNumber),
CONSTRAINT BlogStoryVersionToUserProfile_FK FOREIGN KEY (AuthorId)
REFERENCES UserProfile (UserId),
CONSTRAINT DatesSuccession_CK CHECK (UpdatedDateTime > CreatedDateTime) --Let us hope that MySQL will finally enforce CHECK constraints in a near future version.
);
Getestet in dieser SQL-Geige , die unter MySQL 5.6 ausgeführt wird.
Der BlogStory
Tisch
Wie Sie im Demo-Design sehen können, habe ich die BlogStory
Spalte PRIMARY KEY (PK der Kürze halber) mit dem Datentyp INT definiert. In diesem Zusammenhang möchten Sie möglicherweise einen integrierten automatischen Prozess festlegen, der in jeder Zeileneinfügung einen numerischen Wert für eine solche Spalte generiert und zuweist. Wenn es Ihnen nichts ausmacht, gelegentlich Lücken in diesem Wertesatz zu lassen, können Sie das Attribut AUTO_INCREMENT verwenden , das häufig in MySQL-Umgebungen verwendet wird.
Wenn Sie alle Ihre individuellen BlogStory.CreatedDateTime
Datenpunkte eingeben, können Sie die Funktion NOW () verwenden , die die Datums- und Zeitwerte zurückgibt, die zum genauen Zeitpunkt des INSERT-Vorgangs auf dem Datenbankserver aktuell sind. Diese Praxis ist für mich entschieden geeigneter und weniger fehleranfällig als der Einsatz externer Routinen.
Vorausgesetzt, Sie möchten, wie in den (jetzt entfernten) Kommentaren erläutert, die Möglichkeit vermeiden, BlogStory.Title
doppelte Werte beizubehalten , müssen Sie eine EINZIGARTIGE Einschränkung für diese Spalte einrichten . Aufgrund der Tatsache, dass ein bestimmter Titel von mehreren (oder sogar allen) "früheren" BlogStoryVersions gemeinsam genutzt werden kann , sollte für die Spalte keine EINZIGARTIGE Einschränkung festgelegt werden BlogStoryVersion.Title
.
Ich habe die BlogStory.IsActive
Spalte vom Typ BIT (1) eingefügt (obwohl auch ein TINYINT verwendet werden kann), falls Sie die Funktion "soft" oder "logical" DELETE bereitstellen müssen.
Details zur BlogStoryVersion
Tabelle
Andererseits setzt sich die PK der BlogStoryVersion
Tabelle aus (a) BlogStoryNumber
und (b) einer Spalte zusammen CreatedDateTime
, die natürlich den genauen Zeitpunkt kennzeichnet, zu dem eine BlogStory
Zeile ein INSERT durchlief.
BlogStoryVersion.BlogStoryNumber
Ist nicht nur Teil der PK, sondern auch ein FOREIGN KEY (FK), der auf BlogStory.BlogStoryNumber
eine Konfiguration verweist , die die referenzielle Integrität zwischen den Zeilen dieser beiden Tabellen erzwingt . Insofern ist die Implementierung einer automatischen Generierung von a BlogStoryVersion.BlogStoryNumber
nicht erforderlich, da die in diese Spalte eingefügten Werte als FK aus den Werten "gezogen" werden müssen, die bereits im zugehörigen BlogStory.BlogStoryNumber
Gegenstück enthalten sind.
Die BlogStoryVersion.UpdatedDateTime
Spalte sollte wie erwartet den Zeitpunkt beibehalten, zu dem eine BlogStory
Zeile geändert und folglich der BlogStoryVersion
Tabelle hinzugefügt wurde . Daher können Sie die Funktion NOW () auch in dieser Situation verwenden.
Das Intervall zwischen BlogStoryVersion.CreatedDateTime
und BlogStoryVersion.UpdatedDateTime
drückt den gesamten Zeitraum aus, in dem eine BlogStory
Zeile „vorhanden“ oder „aktuell“ war.
Überlegungen zu einer Version
Spalte
Es kann nützlich sein, sich BlogStoryVersion.CreatedDateTime
die Spalte vorzustellen , die den Wert enthält, der eine bestimmte „frühere“ Version einer BlogStory darstellt . Ich halte dies viel günstiger als ein VersionId
oder VersionCode
, da sie benutzerfreundlicher in dem Sinne, dass Menschen mit sein vertrauten neigen Zeit Konzepten. Die Blog-Autoren oder -Leser könnten beispielsweise auf eine BlogStoryVersion wie folgt verweisen :
- „Ich möchte die spezifische sehen Version des BlogStory durch identifiziert Zahl
1750
, die wurde Erstellt am 26 August 2015
an 9:30
“.
Die Autoren- und Herausgeberrollen : Datenableitung und Interpretation
Mit diesem Ansatz können Sie leicht unterscheiden, wer das „Original“ AuthorId
einer konkreten BlogStory besitzt. Wählen Sie die „früheste“ Version einer bestimmten BlogStoryId
FROM- BlogStoryVersion
Tabelle aus, indem Sie die MIN () -Funktion auf anwenden BlogStoryVersion.CreatedDateTime
.
Auf diese Weise gibt jeder BlogStoryVersion.AuthorId
Wert, der in allen Zeilen "später" oder "nachfolgender" Versionen enthalten ist , natürlich die Autorenkennung der jeweiligen Version an, aber man kann auch sagen, dass ein solcher Wert gleichzeitig bezeichnet die Rolle der beteiligten gespielt Benutzer als Editor der „Original“ Version eines BlogStory .
Ja, ein gegebener AuthorId
Wert kann von mehreren BlogStoryVersion
Zeilen geteilt werden , aber dies ist tatsächlich eine Information, die etwas sehr Wichtiges über jede Version aussagt , so dass die Wiederholung dieses Datums kein Problem darstellt.
Das Format der DATETIME-Spalten
Was den Datentyp DATETIME betrifft, haben Sie Recht: „ MySQL ruft DATETIME-Werte im YYYY-MM-DD HH:MM:SS
Format ' ' ab und zeigt sie an “, aber Sie können die relevanten Daten auf diese Weise sicher eingeben, und wenn Sie eine Abfrage durchführen müssen, müssen Sie nur Nutzen Sie die eingebauten Funktionen DATE und TIME , um unter anderem die betreffenden Werte in dem für Ihre Benutzer geeigneten Format anzuzeigen. Oder Sie können diese Art der Datenformatierung sicher über den Code Ihres Anwendungsprogramms durchführen.
Auswirkungen von BlogStory
UPDATE-Operationen
Jedes Mal, wenn eine BlogStory
Zeile ein UPDATE erleidet, müssen Sie sicherstellen, dass die entsprechenden Werte, die bis zur Änderung „vorhanden“ waren, dann in die BlogStoryVersion
Tabelle eingefügt werden . Ich empfehle daher dringend, diese Operationen in einer einzigen ACID TRANSACTION durchzuführen, um sicherzustellen , dass sie als unteilbare Arbeitseinheit behandelt werden. Sie können TRIGGERS auch einsetzen, aber sie neigen dazu, die Dinge sozusagen unordentlich zu machen.
Einführen einer VersionId
oder VersionCode
Spalte
Wenn Sie sich (aufgrund geschäftlicher Umstände oder persönlicher Vorlieben) dafür entscheiden, eine BlogStory.VersionId
oder BlogStory.VersionCode
-Spalte zur Unterscheidung der BlogStoryVersions einzufügen , sollten Sie über die folgenden Möglichkeiten nachdenken:
Es VersionCode
kann erforderlich sein, dass A in (i) der gesamten BlogStory
Tabelle und auch in (ii) EINZIGARTIG ist BlogStoryVersion
.
Daher müssen Sie eine sorgfältig getestete und absolut zuverlässige Methode implementieren, um jeden Code
Wert zu generieren und zuzuweisen .
Möglicherweise VersionCode
könnten die Werte in verschiedenen BlogStory
Zeilen wiederholt werden , jedoch niemals zusammen mit denselben dupliziert werden BlogStoryNumber
. ZB könntest du haben:
- eine BlogStoryNumber
3
- Version83o7c5c
und gleichzeitig
- eine BlogStoryNumber
86
- Version83o7c5c
und
- eine BlogStoryNumber
958
- Version83o7c5c
.
Die spätere Möglichkeit eröffnet eine weitere Alternative:
Halten Sie ein VersionNumber
für BlogStories
, so könnte es sein:
- BlogStoryNumber
23
- Versionen1, 2, 3…
;
- BlogStoryNumber
650
- Versionen1, 2, 3…
;
- BlogStoryNumber
2254
- Versionen1, 2, 3…
;
- etc.
Halten Sie "ursprüngliche" und "nachfolgende" Versionen in einer einzigen Tabelle
Obwohl Beibehaltung aller BlogStoryVersions in der gleichen individuellen Basistabelle ist möglich, schlage ich vor, es nicht zu tun , weil Sie zwei unterschiedliche (konzeptionelle) Arten von Tatsachen Vermischung würden, die damit unerwünschte Nebenwirkungen auf
- Datenbeschränkungen und -manipulation (auf logischer Ebene) sowie
- die damit verbundene Verarbeitung und Speicherung (auf der physischen Ebene).
Unter der Voraussetzung, dass Sie sich für diese Vorgehensweise entscheiden, können Sie dennoch viele der oben beschriebenen Ideen nutzen, z.
- eine zusammengesetzte PK, die aus einer INT-Spalte (
BlogStoryNumber
) und einer DATETIME-Spalte ( CreatedDateTime
) besteht;
- die Nutzung von Serverfunktionen zur Optimierung der dazugehörigen Prozesse und
- die vom Autor und Herausgeber ableitbaren Rollen .
Wenn Sie mit einem solchen Ansatz fortfahren, wird ein BlogStoryNumber
Wert dupliziert , sobald „neuere“ Versionen hinzugefügt werden. Eine Option, die Sie auswerten können (die den im vorherigen Abschnitt erwähnten sehr ähnlich ist), erstellt eine BlogStory
PK bestehend aus den Spalten BlogStoryNumber
und VersionCode
man auf diese Weise eindeutig wäre in der Lage , um jede zu identifizieren Version eines BlogStory . Und Sie können es mit einer Kombination von BlogStoryNumber
und versuchen VersionNumber
.
Ähnliches Szenario
Vielleicht finden Sie meine Antwort auf diese Frage der Hilfe, da ich auch vorschlage, zeitliche Fähigkeiten in der betreffenden Datenbank zu aktivieren , um mit einem vergleichbaren Szenario fertig zu werden.
author_id
in jeder Zeile der Tabelle wiederholt wird. Wo und wie soll ich es aufbewahren ?