Menganalisis skenario — yang menyajikan karakteristik yang terkait dengan subjek yang dikenal sebagai basis data temporal - dari perspektif konseptual, orang dapat menentukan bahwa: (a) Versi Blog Story yang “ada” dan (b) Versi Story Blog yang “dulu” , meskipun sangat menyerupai, adalah entitas dari tipe yang berbeda.
Selain itu, ketika bekerja pada tingkat abstraksi yang logis, fakta (diwakili oleh baris) dari jenis yang berbeda harus disimpan dalam tabel yang berbeda. Dalam kasus yang dipertimbangkan, bahkan ketika sangat mirip, (i) fakta tentang Versi "sekarang" berbeda dari (ii) fakta tentang Versi "masa lalu" .
Karena itu saya sarankan mengelola situasi dengan dua tabel:
satu didedikasikan khusus untuk Versi "saat ini" atau "sekarang" dari Cerita Blog , dan
yang terpisah, tetapi juga terkait dengan yang lain, untuk semua Versi "sebelumnya" atau "masa lalu" ;
masing-masing dengan (1) jumlah kolom yang sedikit berbeda dan (2) kelompok kendala yang berbeda.
Kembali ke lapisan konseptual, saya menganggap bahwa — di lingkungan bisnis Anda — Penulis dan Editor adalah gagasan yang dapat digambarkan sebagai Peran yang dapat dimainkan oleh Pengguna , dan aspek-aspek penting ini bergantung pada derivasi data (melalui operasi manipulasi tingkat logis) dan interpretasi (yang dilakukan oleh Blog Stories, pembaca dan penulis, di tingkat eksternal sistem informasi yang terkomputerisasi, dengan bantuan satu atau lebih program aplikasi).
Saya akan merinci semua faktor ini dan poin terkait lainnya sebagai berikut.
Peraturan bisnis
Menurut pemahaman saya tentang persyaratan Anda, formulasi aturan bisnis berikut (disatukan dalam hal jenis entitas yang relevan dan jenis hubungan timbal baliknya) sangat membantu dalam membangun skema konseptual yang sesuai :
- Seorang Pengguna menulis BlogStories nol-satu-atau-banyak
- Sebuah BlogStory memegang nol-satu-atau-banyak BlogStoryVersions
- Seorang Pengguna menulis BlogStoryVersions nol-satu-atau-banyak
Diagram Eksposisi IDEF1X
Akibatnya, dalam rangka untuk menjelaskan saran saya berdasarkan perangkat grafis, saya telah membuat sebuah sampel IDEF1X sebuah diagram yang berasal dari aturan bisnis dirumuskan di atas dan fitur lain yang tampaknya bersangkutan. Itu ditunjukkan pada Gambar 1 :
Mengapa BlogStory dan BlogStoryVersion dikonseptualisasikan sebagai dua jenis entitas yang berbeda?
Karena:
Contoh BlogStoryVersion (yaitu, "masa lalu" satu) selalu memegang nilai untuk properti UpdatedDateTime , sementara kemunculan BlogStory (yaitu, "sekarang") tidak pernah memegangnya.
Selain itu, entitas dari tipe-tipe tersebut secara unik diidentifikasi oleh nilai-nilai dari dua set properti yang berbeda: BlogStoryNumber (dalam kasus kemunculan BlogStory ), dan BlogStoryNumber plus CreatedDateTime (dalam kasus contoh BlogStoryVersion ).
a Definisi Integrasi untuk Information Modeling ( IDEF1X ) adalah teknik pemodelan data yang sangat dianjurkan yang didirikan sebagai standar pada Desember 1993 oleh Amerika Serikat Institut Nasional Standar dan Teknologi (NIST). Hal ini didasarkan pada materi teori awal yang ditulis oleh satu-satunya pencetus dari model relasional , yaitu, Dr EF Codd ; pada tampilan Entity-Relationship data, yang dikembangkan oleh Dr. PP Chen ; dan juga pada Teknik Desain Basis Data Logis, yang dibuat oleh Robert G. Brown.
Ilustrasi tata letak SQL-DDL yang logis
Kemudian, berdasarkan analisis konseptual yang disajikan sebelumnya, saya menyatakan desain tingkat logis di bawah ini:
-- 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.
);
Diuji dalam SQL Fiddle ini yang berjalan pada MySQL 5.6.
The BlogStory
table
Seperti yang Anda lihat dalam desain demo, saya telah mendefinisikan kolom BlogStory
PRIMARY KEY (PK for brevity) dengan datatype INT. Dalam hal ini, Anda mungkin ingin memperbaiki proses otomatis bawaan yang menghasilkan dan menetapkan nilai numerik untuk kolom tersebut di setiap penyisipan baris. Jika Anda tidak keberatan meninggalkan celah sesekali dalam rangkaian nilai ini, maka Anda dapat menggunakan atribut AUTO_INCREMENT , yang biasa digunakan dalam lingkungan MySQL.
Saat memasukkan semua BlogStory.CreatedDateTime
titik data individual Anda, Anda dapat memanfaatkan fungsi SEKARANG () , yang mengembalikan nilai Tanggal dan Waktu yang saat ini ada di server database pada saat operasi INSERT yang tepat. Bagi saya, praktik ini jelas lebih cocok dan kurang rentan terhadap kesalahan daripada penggunaan rutin eksternal.
Asalkan, sebagaimana dibahas dalam komentar (sekarang dihapus), Anda ingin menghindari kemungkinan mempertahankan BlogStory.Title
nilai duplikat, Anda harus menyiapkan batasan UNIK untuk kolom ini. Karena kenyataan bahwa Judul yang diberikan dapat dibagikan oleh beberapa (atau bahkan semua) BlogStoryVersions "masa lalu" , maka batasan UNIK tidak boleh dibuat untuk BlogStoryVersion.Title
kolom.
Saya menyertakan BlogStory.IsActive
kolom tipe BIT (1) (meskipun TINYINT mungkin juga digunakan) jika Anda perlu menyediakan fungsionalitas DELETE "lunak" atau "logis".
Detail tentang BlogStoryVersion
tabel
Di sisi lain, PK BlogStoryVersion
tabel terdiri dari (a) BlogStoryNumber
dan (b) kolom bernama CreatedDateTime
itu, tentu saja, menandai instan tepat di mana BlogStory
baris menjalani INSERT.
BlogStoryVersion.BlogStoryNumber
, selain sebagai bagian dari PK, juga dibatasi sebagai KUNCI LUAR NEGERI (FK) yang merujuk BlogStory.BlogStoryNumber
, konfigurasi yang menegakkan integritas referensial antara baris dari dua tabel ini. Dalam hal ini, BlogStoryVersion.BlogStoryNumber
tidak diperlukan penerapan generasi otomatis karena, jika ditetapkan sebagai FK, nilai-nilai yang DICANTUMKAN ke dalam kolom ini harus "diambil dari" yang sudah terlampir dalam BlogStory.BlogStoryNumber
mitra terkait .
The BlogStoryVersion.UpdatedDateTime
kolom harus mempertahankan, seperti yang diharapkan, titik waktu ketika sebuah BlogStory
baris dimodifikasi dan, sebagai akibatnya, ditambahkan ke BlogStoryVersion
meja. Karenanya, Anda dapat menggunakan fungsi SEKARANG () dalam situasi ini juga.
The Interval dipahami antara BlogStoryVersion.CreatedDateTime
dan BlogStoryVersion.UpdatedDateTime
mengungkapkan seluruh Periode selama mana BlogStory
berturut-turut adalah “hadir” atau “saat ini”.
Pertimbangan untuk Version
kolom
Hal ini dapat berguna untuk dianggap BlogStoryVersion.CreatedDateTime
sebagai kolom yang menyimpan nilai yang mewakili Versi “masa lalu” dari BlogStory . Saya menganggap ini jauh lebih bermanfaat daripada VersionId
atau VersionCode
, karena lebih ramah pengguna dalam arti bahwa orang cenderung lebih akrab dengan konsep waktu . Misalnya, penulis atau pembaca blog dapat merujuk ke BlogStoryVersion dengan cara yang serupa dengan yang berikut:
- “Saya ingin melihat spesifik Versi dari BlogStory diidentifikasi oleh Nomor
1750
yang Dibuat pada 26 August 2015
di 9:30
”.
Peran Penulis dan Editor : Derivasi dan interpretasi data
Dengan pendekatan ini, Anda dapat dengan mudah membedakan yang memegang “asli” AuthorId
dari beton BlogStory memilih “awal” Versi dari tertentu BlogStoryId
DARI BlogStoryVersion
table berdasarkan menerapkan fungsi MIN () ke BlogStoryVersion.CreatedDateTime
.
Dengan cara ini, setiap BlogStoryVersion.AuthorId
nilai yang terkandung dalam semua baris Versi "nanti" atau "berhasil" menunjukkan, tentu saja, pengenal Penulis dari masing-masing Versi yang ada, tetapi orang juga dapat mengatakan bahwa nilai tersebut adalah, pada saat yang sama, menunjukkan yang Peran yang dimainkan oleh terlibat Pengguna sebagai Editor dari “asli” Versi dari BlogStory .
Ya, AuthorId
nilai yang diberikan dapat dibagi oleh beberapa BlogStoryVersion
baris, tetapi ini sebenarnya adalah sepotong informasi yang mengatakan sesuatu yang sangat signifikan tentang masing-masing Versi , sehingga pengulangan kata datum tidak menjadi masalah.
Format kolom DATETIME
Adapun tipe data DATETIME, ya, Anda benar, “ MySQL mengambil dan menampilkan nilai DATETIME dalam YYYY-MM-DD HH:MM:SS
format ' ' , tetapi Anda dapat dengan percaya diri memasukkan data terkait dengan cara ini, dan ketika Anda harus melakukan kueri, Anda hanya perlu make penggunaan built-in tanggal dan waktu fungsi untuk, antara lain, menunjukkan nilai-nilai tentang dalam format yang sesuai untuk pengguna Anda. Atau Anda tentu saja dapat melakukan pemformatan data semacam ini melalui kode program aplikasi Anda.
Implikasi BlogStory
operasi UPDATE
Setiap kali BlogStory
baris mengalami UPDATE, Anda harus memastikan bahwa nilai-nilai yang sesuai yang "hadir" sampai modifikasi terjadi kemudian dimasukkan ke dalam BlogStoryVersion
tabel. Karenanya, saya sangat menyarankan untuk memenuhi operasi ini dalam satu TRANSAKSI ASAM untuk menjamin bahwa mereka diperlakukan sebagai Unit Kerja yang tidak dapat dibagi. Anda mungkin juga mempekerjakan PEMICU, tetapi mereka cenderung membuat segala sesuatunya berantakan.
Memperkenalkan kolom VersionId
atau aVersionCode
Jika Anda memilih (karena keadaan bisnis atau preferensi pribadi) untuk memasukkan kolom BlogStory.VersionId
atau BlogStory.VersionCode
untuk membedakan BlogStoryVersions , Anda harus merenungkan kemungkinan berikut:
A VersionCode
dapat diminta menjadi UNIK dalam (i) seluruh BlogStory
tabel dan juga dalam (ii) BlogStoryVersion
.
Oleh karena itu, Anda harus menerapkan metode yang telah diuji dengan cermat dan benar-benar andal untuk menghasilkan dan menetapkan setiap Code
nilai.
Mungkin, VersionCode
nilai bisa diulang dalam BlogStory
baris yang berbeda , tetapi tidak pernah diduplikasi bersamaan dengan nilai yang sama BlogStoryNumber
. Misalnya, Anda dapat memiliki:
- a BlogStoryNumber
3
- Versi83o7c5c
dan, secara bersamaan,
- a BlogStoryNumber
86
- Versi83o7c5c
dan
- a BlogStoryNumber
958
- Version83o7c5c
.
Kemungkinan selanjutnya membuka alternatif lain:
Menyimpan VersionNumber
untuk BlogStories
, jadi mungkin ada:
- BlogStoryNumber
23
- Versi1, 2, 3…
;
- BlogStoryNumber
650
- Versi1, 2, 3…
;
- BlogStoryNumber
2254
- Versi1, 2, 3…
;
- dll.
Memegang versi "asli" dan "berikutnya" dalam satu tabel
Meskipun mempertahankan semua BlogStoryVersions di tabel dasar individu yang sama adalah mungkin, saya sarankan untuk tidak melakukannya karena Anda akan mencampur dua jenis fakta (konseptual) yang berbeda, yang dengan demikian memiliki efek samping yang tidak diinginkan pada
- kendala dan manipulasi data (pada tingkat logis), bersama dengan
- pemrosesan dan penyimpanan terkait (pada tingkat fisik).
Tetapi, dengan syarat Anda memilih untuk mengikuti tindakan itu, Anda masih dapat memanfaatkan banyak gagasan yang dirinci di atas, misalnya:
- sebuah komposit PK yang terdiri dari kolom INT (
BlogStoryNumber
) dan kolom DATETIME ( CreatedDateTime
);
- penggunaan fungsi server untuk mengoptimalkan proses terkait, dan
- Peran yang dapat diturunkan dari Penulis dan Editor .
Melihat bahwa, dengan melanjutkan pendekatan semacam itu, suatu BlogStoryNumber
nilai akan digandakan segera setelah Versi "yang lebih baru" ditambahkan, opsi yang dan yang dapat Anda evaluasi (yang sangat mirip dengan yang disebutkan di bagian sebelumnya) adalah membangun sebuah BlogStory
PK. terdiri dari kolom BlogStoryNumber
dan VersionCode
, dengan cara ini Anda akan dapat secara unik mengidentifikasi setiap Versi dari BlogStory . Dan Anda dapat mencoba dengan kombinasi BlogStoryNumber
dan VersionNumber
juga.
Skenario serupa
Anda dapat menemukan jawaban saya untuk pertanyaan bantuan ini, karena saya juga mengusulkan kemampuan sementara yang memungkinkan dalam database terkait untuk menangani skenario yang sebanding.
author_id
bidang kueri yang berulang di setiap setiap baris tabel. Di mana dan bagaimana saya harus menyimpannya ?