Аналізуючи сценарій - який представляє характеристики, пов’язані з предметом, відомим як тимчасові бази даних - з концептуальної точки зору можна визначити, що: (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
теж.
Аналогічний сценарій
Ви можете знайти мою відповідь на це питання допомоги, оскільки я також пропоную дозволити тимчасовим можливостям у відповідній базі даних вирішувати порівняний сценарій.