Аналізуючи сценарій - який представляє характеристики, пов’язані з предметом, відомим як тимчасові бази даних - з концептуальної точки зору можна визначити, що: (a) "теперішня" версія Story Blog Blog і (b) "минула" версія Story Blog Blog , хоча дуже схожі, є сутностями різних типів.
На додаток до цього, працюючи на логічному рівні абстракції, факти (представлені рядками) різних видів повинні зберігатися у різних таблицях. У розглянутому випадку, навіть коли досить схожі, (i) факти про "теперішні" Версії відрізняються від (ii) факти про "минулі" Версії .
Тому я рекомендую керувати ситуацією за допомогою двох таблиць:
один призначено винятково для «поточної» або «справжньої» Версії цих історій Щоденника , і
той, який є окремим, але також пов'язаний з іншим, для всіх "попередніх" або "минулих" версій ;
кожен з (1) трохи виразною кількістю стовпців і (2) різною групою обмежень.
Назад до концептуального шару, я вважаю , що -in ваш бізнес для навколишнього середовища Автор і редактор є поняттями , які можуть бути окреслені в якості ролей , які можуть бути відтворені на користувача , і ці важливі аспекти залежать від даних виведення ( з допомогою операцій маніпулювання логічного рівня) та інтерпретація (проводиться читачами та письменниками Blog Stories на зовнішньому рівні комп’ютеризованої інформаційної системи за сприяння однієї або декількох прикладних програм).
Я детально деталізую всі ці фактори та інші відповідні моменти наступним чином.
Правила бізнесу
Згідно з моїм розумінням ваших вимог, наступні формулювання бізнес-правил (складені у відповідності до відповідних типів суб'єктів господарювання та їх видів взаємозв'язків) є особливо корисними для створення відповідної концептуальної схеми:
- Користувач пише нуль-один-або-багатьох BlogStories
- BlogStory має нульовий один або багатьом BlogStoryVersions
- Користувач написав нуль-один-або-багатьох BlogStoryVersions
Діаграма IDEF1X експозиції
Отже, для того , щоб викласти свою пропозицію в силі графічного пристрою, я створив зразок IDEF1x діаграма , яка є похідною від бізнесу - правил , сформульованих вище , та інших функцій , які здаються доречними. Це показано на малюнку 1 :

Чому BlogStory та BlogStoryVersion концептуалізуються як два різні типи сутності?
Оскільки:
BlogStoryVersion екземпляр (тобто, «минуле» один) завжди має значення для UpdatedDateTime власності, в той час як BlogStory явище (тобто, «справжній» один) ніколи не утримує його.
Крім того, сутності цих типів однозначно ідентифікуються за значеннями двох різних наборів властивостей: BlogStoryNumber (у випадку подій BlogStory ) та BlogStoryNumber плюс CreatedDateTime (у випадку екземплярів BlogStoryVersion ).
Визначення інтеграції для інформаційного моделювання ( IDEF1X ) є високо рекомендовані дані моделювання методомякий був створенийякості стандарту в грудні 1993 року США Національним інститутом стандартів і технологій (NIST). Він заснований на ранньому теоретичному матеріалі авторство єдиним винуватцем у реляційну моделі , тобто д - р Ф. Кодда ; напогляд даних про відносини між особами та особами, розроблений доктором П.П. Ченом ; а також про техніку дизайну логічної бази даних, створену Робертом Г. Брауном.
Ілюстративний логічний макет SQL-DDL
Потім, грунтуючись на концептуальному аналізі, представленому раніше, я оголосив проект логічного рівня нижче:
-- 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.
);
Перевірено в цій скрипті SQL, який працює на MySQL 5.6.
BlogStoryстіл
Як ви бачите в демонстраційному дизайні, я визначив BlogStoryстовпець PRIMARY KEY (ПК для стислості) з типом даних INT. У зв'язку з цим, можливо, ви хочете виправити вбудований автоматичний процес, який генерує та призначає числове значення для такого стовпця в кожній вставці рядка. Якщо ви не заперечуєте час від часу залишати прогалини в цьому наборі значень, тоді ви можете використовувати атрибут AUTO_INCREMENT , який зазвичай використовується в середовищах MySQL.
Вводячи всі ваші індивідуальні BlogStory.CreatedDateTimeточки даних, ви можете використовувати функцію NOW () , яка повертає значення Дати та Часу, які є поточними на сервері баз даних у той самий момент операції ВСТУП. Для мене ця практика, очевидно, більше підходить і менш схильна до помилок, ніж використання зовнішніх процедур.
За умови, що, як було обговорено у коментарях (тепер видалених), ви хочете уникнути можливості збереження BlogStory.Titleдублікатів значень, ви повинні встановити UNIQUE обмеження для цього стовпця. Через те, що даний Заголовок може бути спільним для декількох (або навіть усіх) "минулих" BlogStoryVersions , тоді Унікальне обмеження для колонки не повинно встановлюватися BlogStoryVersion.Title.
Я включив BlogStory.IsActiveстовпець типу BIT (1) (хоча TINYINT також може бути використаний) у випадку, якщо вам потрібно забезпечити функцію «м'якого» або «логічного» DELETE.
Детальніше про BlogStoryVersionтаблицю
З іншого боку, ПК BlogStoryVersionтаблиці складається з (а) BlogStoryNumberта (б) стовпця з назвою, CreatedDateTimeякий, звичайно, позначає точний момент, у якому BlogStoryряд зазнав ВСТУП.
BlogStoryVersion.BlogStoryNumberокрім того, що є частиною ПК, також обмежується як ЗАМЕЧНИЙ КЛЮЧ (FK), який посилається BlogStory.BlogStoryNumber, конфігурація, що забезпечує референтну цілісність між рядками цих двох таблиць. У цьому відношенні реалізація автоматичної генерації a BlogStoryVersion.BlogStoryNumberне є необхідною, оскільки, встановлюючи як FK, значення ВСТАНОВЛЕННЯ в цей стовпець повинні бути "виведені" з тих, які вже вкладені у відповідний BlogStory.BlogStoryNumberаналог.
У BlogStoryVersion.UpdatedDateTimeстовпці, як очікується, слід зберігати момент часу, коли BlogStoryрядок було змінено і, як наслідок, додано до BlogStoryVersionтаблиці. Отже, ви можете використовувати функцію NOW () і в цій ситуації.
Інтервал обгорнула між BlogStoryVersion.CreatedDateTimeі BlogStoryVersion.UpdatedDateTimeвисловлює весь Період , в протягом якого BlogStoryрядок була «присутній» або «поточний».
Міркування для Versionстовпчика
Це може бути корисно думати BlogStoryVersion.CreatedDateTimeяк стовпець , який містить значення , яке представляє собою окрему «минуле» версію про більш BlogStory . Я вважаю це набагато вигідніше, ніж VersionIdабо VersionCode, оскільки це зручніше для користувачів в тому сенсі, що люди, як правило, більш знайомі з поняттями часу . Наприклад, автори блогу чи читачі можуть посилатися на BlogStoryVersion у такий спосіб, як:
- «Я хочу побачити специфіку Версія в BlogStory ідентифікованої Номер
1750 , який був Created на 26 August 2015в 9:30».
Автор і редактор Ролі: Висновок даних і інтерпретація
При такому підході можна легко розрізнити , хто тримає «оригінал» AuthorIdз бетону BlogStory , що вибирає «рання» версію певних BlogStoryIdІЗ BlogStoryVersionтаблиці в силі застосування функції MIN () для BlogStoryVersion.CreatedDateTime.
Таким чином, кожне BlogStoryVersion.AuthorIdзначення, що міститься у всіх рядках "пізнішої" або "успішної" версій, вказує, природно, ідентифікатор автора відповідної версії , але також можна сказати, що таке значення одночасно позначає роль грає залученого користувача в якості редактора в «оригінальній» версії у вигляді BlogStory .
Так, даність AuthorId значення може бути розділене кількома BlogStoryVersionрядками, але це насправді інформація, яка розповідає щось дуже важливе про кожну Версію , тому повторення зазначеної дати не є проблемою.
Формат стовпців DATETIME
Що стосується типу даних DATETIME, так, ви праві, " MySQL отримує та відображає значення DATETIME у YYYY-MM-DD HH:MM:SSформаті " ", але ви можете впевнено вводити відповідні дані таким чином, і коли вам потрібно виконати запит, вам просто потрібно скористайтеся вбудованими функціями DATE та TIME , щоб, серед іншого, показати відповідні значення у відповідному форматі для ваших користувачів. Або ви, безумовно, могли б здійснити подібне форматування даних за допомогою програм (-ів) програми.
Наслідки BlogStoryоперацій UPDATE
Кожен раз, коли BlogStoryрядок зазнає ОНОВЛЕННЯ, ви повинні це забезпечити що відповідні значення, які були "присутніми" до зміни, потім ВСТАВЛЯються в BlogStoryVersionтаблицю. Таким чином, я настійно пропоную виконати ці операції в рамках однієї ОСВІТИ КИСЛОТИ, щоб гарантувати, що до них відносяться як до неподільної одиниці роботи. Ви також можете використовувати TRIGGERS, але вони, як правило, роблять речі неохайними.
Представляємо a VersionId або VersionCodeколонку
Якщо ви вирішите (з огляду на бізнес-обставини чи особисті переваги), додайте стовпчик BlogStory.VersionIdабо BlogStory.VersionCodeстовпчик, щоб виділити це BlogStoryVersions , вам слід задуматися про наступні можливості:
А VersionCode може вимагати бути УНІКАЛЬНИМ у (i) всій BlogStoryтаблиці, а також у (ii) BlogStoryVersion.
Тому вам потрібно реалізувати ретельно перевірений та абсолютно надійний метод, щоб створити та призначити коженCode значення.
Можливо, VersionCodeзначення можуть повторюватися в різних BlogStoryрядках, але ніколи не дублюватися разом з одними і тими жBlogStoryNumber . Наприклад, ви могли б мати:
- BlogStoryNumber
3 - версія83o7c5c і, одночасно,
- BlogStoryNumber
86 - версія83o7c5c та
- BlogStoryNumber
958- версія83o7c5c .
Пізніша можливість відкриває ще одну альтернативу:
Збереження VersionNumberдля BlogStories, так що можуть бути:
- BlogStoryNumber
23- версії1, 2, 3… ;
- BlogStoryNumber
650- версії1, 2, 3… ;
- BlogStoryNumber
2254- версії1, 2, 3… ;
- тощо.
Зберігання «оригінальної» та «наступної» версій в одній таблиці
Хоча підтримка всіх BlogStoryVersions в одній індивідуальній базовій таблиці можлива, я пропоную цього не робити, оскільки ви змішали б два різних (концептуальні) типи фактів, що, таким чином, має небажані побічні ефекти на
- обмеження даних та маніпулювання (на логічному рівні) разом з
- пов'язана обробка та зберігання (на фізичному рівні).
Але за умови, що ви вирішите слідувати цьому курсу дій, ви все ще можете скористатися багатьма ідеями, детально описаними вище, наприклад:
- композит ПК , що складається з шпальти INT (
BlogStoryNumber) і стовпці DATETIME ( CreatedDateTime);
- використання серверних функцій з метою оптимізації відповідних процесів та
- Автор і редактор виведені Ролі .
Бачачи, що, продовжуючи такий підхід, BlogStoryNumberзначення буде дублюватися, як тільки будуть додані "новіші" версії , варіант, який і ви могли б оцінити (який дуже схожий на ті, що згадувались у попередньому розділі), встановлює BlogStoryПК що складається з колон BlogStoryNumberі VersionCode, таким чином , ви могли б однозначно ідентифікувати кожну версію у виді BlogStory . І ви можете спробувати з комбінацією BlogStoryNumberтаVersionNumber теж.
Аналогічний сценарій
Ви можете знайти мою відповідь на це питання допомоги, оскільки я також пропоную дозволити тимчасовим можливостям у відповідній базі даних вирішувати порівняний сценарій.