Концептуально кажучи, хоча у вашому бізнес-середовищі Порядок та Адреса - це ідеї, тісно пов’язані між собою, вони по суті є двома окремими типами об'єктів, кожен зі своїм набором застосовних властивостей (або атрибутів) та обмежень.
Тому, як було сказано раніше в коментарях, я погоджуюся з @Erik , і вам слід організувати логічний макет вашої бази даних, декларується серед інших елементів:
- один дискретний стіл , щоб адресна частина інформації;
- одна таблиця для збереження специфічних для клієнта деталей;
- одна таблиця для додавання точок даних замовлення ; і
- одна таблиця, яка містить факти про асоціації між клієнтами та адресами ;
як я поясню нижче.
Діаграма IDEF1X експозиторії
Малюнок вартує тисячі слів, тому я створив діаграму IDEF1X, показану на малюнку 1, щоб проілюструвати деякі можливості, відкриті моєю пропозицією:
Замовник , Адреса та їх асоціації
Як було продемонстровано, я зобразив асоціацію з коефіцієнтом кардинальності «багато до багатьох» (M: N) між типами сутності клієнта a та Адреса ; такий підхід забезпечить майбутню гнучкість, оскільки, як відомо, Клієнт може зберігати кілька адрес протягом певного часу, або навіть одночасно, і одну і ту ж адресу можуть надавати декілька клієнтів .
Конкретна адреса може бути використана декількома способами клієнтами від одного до багатьох (1: M) ; наприклад, його можна визначити як фізичний , та / або встановити для доставки та / або для виставлення рахунків . Можливо, той самий екземпляр адреси може одночасно служити кожній із вищезгаданих цілей, або він може охоплювати два використання, тоді як інше входження адреси охоплює решту.
a У деяких бізнес-середовищах Замовник може бути або Особою, або Організацією (ситуація, яка передбачає дещо чітке домовленість, як детально описано у цій відповіді про структуру підтипу підтипу), але з метою надання спрощеного прикладу, я вирішив не включати цю можливість сюди. Якщо вам потрібно висвітлити цю ситуацію у вашій базі даних, пост попереднього посилання показує спосіб вирішення зазначеної вимоги.
Замовлення , адреса , CustomerAddress і адреси Ролі
Зазвичай для замовлення потрібні лише два види адреси , одна для доставки та одна для виставлення рахунків . Таким чином, один і той же екземпляр адреси міг би заповнити обидві ролі для окремого замовлення , але кожну роль зображено відповідною властивістю, тобто ShippingAddressId або BillingAddressId .
Замовлення пов'язаний з адресою через CustomerAddress типу асоціативної сутності за допомогою два мульти-власності іноземних ключів, тобто
- ( CustomerNumber , ShippingAddressId ) та ( CustomerNumber , BillingAddressId ),
і вказуючи на CustomerAddress декількох властивостей PRIMARY KEY , показаної в
- ( CustomerNumber , AddressId )
... що допомагає представити ділове правило, яке передбачає, що (a) екземпляр замовлення повинен бути пов'язаний виключно з (b) подіями адреси, які раніше були пов'язані з конкретним замовником, який зробив це замовлення , і ніколи з (c) випадковим не- замовником - пов'язана адреса .
Історія для (1) Адреса та для (2) асоціації CustomerAddress
Якщо ви хочете , щоб надати можливість зміни адресних частин інформації, то ви повинні стежити за все зміни даних. Таким чином я зобразив Адреса як "ревізований" тип сутності, який підтримує власну Історію адреси .
Оскільки характер зв'язку між Клієнтом та Адресою також може зазнати однієї або декількох модифікацій, я також змальовував можливість обробляти таку асоціацію як "ревізійну" в силу типу юридичної особи CustomerAddressHistory .
У цьому відношенні різні фактори, з якими розглядаються питання Q & A, ні. 1 і Q & A ні. 2 , - що стосується включення тимчасових можливостей у базу даних - дійсно актуальні.
Ілюстративний логічний макет 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 based on the exact
-- data manipulation tendencies of your business domain.
-- As one would expect, you are free to utilize
-- your preferred (or required) naming conventions.
CREATE TABLE Customer (
CustomerNumber INT NOT NULL,
SpecificAttribute CHAR(30) NOT NULL,
ParticularAttribute CHAR(30) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Customer_PK PRIMARY KEY (CustomerNumber)
);
CREATE TABLE Address (
AddressId INT NOT NULL,
SpecificAttribute CHAR(30) NOT NULL,
ParticularAttribute CHAR(30) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Address_PK PRIMARY KEY (AddressId)
);
CREATE TABLE CustomerAddress (
CustomerNumber INT NOT NULL,
AddressId INT NOT NULL,
IsPhysical BIT NOT NULL,
IsShipping BIT NOT NULL,
IsBilling BIT NOT NULL,
IsActive BIT NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT CustomerAddress_PK PRIMARY KEY (CustomerNumber, AddressId),
CONSTRAINT CustomerAddressToCustomer_FK FOREIGN KEY (CustomerNumber)
REFERENCES Customer (CustomerNumber),
CONSTRAINT CustomerAddressToAddress_FK FOREIGN KEY (AddressId)
REFERENCES Address (AddressId)
);
CREATE TABLE MyOrder (
CustomerNumber INT NOT NULL,
OrderNumber INT NOT NULL,
ShippingAddressId INT NOT NULL,
BillingAddressId INT NOT NULL,
SpecificAttribute CHAR(30) NOT NULL,
ParticularAttribute CHAR(30) NOT NULL,
OrderDate DATE NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Order_PK PRIMARY KEY (CustomerNumber, OrderNumber),
CONSTRAINT OrderToCustomer_FK FOREIGN KEY (CustomerNumber)
REFERENCES Customer (CustomerNumber),
CONSTRAINT OrderToShippingAddress_FK FOREIGN KEY (CustomerNumber, ShippingAddressId)
REFERENCES CustomerAddress (CustomerNumber, AddressId),
CONSTRAINT OrderToBillingAddress_FK FOREIGN KEY (CustomerNumber, BillingAddressId)
REFERENCES CustomerAddress (CustomerNumber, AddressId)
);
CREATE TABLE AddressHistory (
AddressId INT NOT NULL,
AuditedDateTime DATETIME NOT NULL,
SpecificAttribute CHAR(30) NOT NULL,
ParticularAttribute CHAR(30) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT AddressHistory_PK PRIMARY KEY (AddressId, AuditedDateTime),
CONSTRAINT AddressHistoryToAddress_FK FOREIGN KEY (AddressId)
REFERENCES Address (AddressId)
);
CREATE TABLE CustomerAddressHistory (
CustomerNumber INT NOT NULL,
AddressId INT NOT NULL,
AuditedDateTime DATETIME NOT NULL,
IsPhysical BIT NOT NULL,
IsShipping BIT NOT NULL,
IsBilling BIT NOT NULL,
IsActive BIT NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT CustomerAddressHistory_PK PRIMARY KEY (CustomerNumber, AddressId, AuditedDateTime),
CONSTRAINT CustomerAddressHistoryToCustomerAddress_FK FOREIGN KEY (CustomerNumber, AddressId)
REFERENCES CustomerAddress (CustomerNumber, AddressId)
);
Якщо ви хочете поглянути, я перевірив це у цій db <> скрипці, яка працює на SQL Server 2017.
У History
таблицях
Наступний уривок із вашого запитання дуже важливий:
Що я шукаю - це те, як я можу налаштувати свої адреси, тож коли я їх редагую, на замовлення не впливає той факт, що клієнт оновлює свою адресу або переїжджає.
AddressHistory
І CustomerAddressHistory
столи допомоги в забезпеченні , що замовлення не залежить від адресних змін, так як всі «попередні» рядки повинні бути збережені у відповідній History
таблиці і можуть бути запитані при необхідності. Операції оновлення та видалення на цих двох таблицях повинні бути заборонені (спроби змінити історію можуть мати навіть негативні юридичні наслідки).
Інтервал охоплює між значеннями , вкладених в AddressHistory.CreatedDateTime
і AddressHistory.AuditedDateTime
виступає за весь період , в протягом якого деяка «минулого» Address
рядок була визнана «присутній», «поточний» або «ефективний». Подібні міркування стосуються CustomerAddressHistory
рядків.
CustomerAddress.IsActive
Стовпець БІТ (логічний) призначаються , щоб вказати, є деяка Address
є «корисною» з допомогою рядка Customer
рядка чи ні; наприклад, якщо для нього встановлено значення "false", це переказує той факт, що Клієнт вже не використовує цю адресу, а значить, не може бути використаний для нових замовлень .
Примітка : З іншого боку, я бачив деякі системи , в яких кожен раз, коли новий замовлення буде здійснюватися в адресному інформації необхідно ввести ( в кілька разів повторно), і адреса (адреса) , які використовуються для останніх Замовлень ніколи не стерті (звідси що замовлення не залежить від адресних змін).
Цей спосіб дії може, безумовно, включати значні обсяги надмірності, але це ймовірність того, що - залежно від точних інформаційних вимог вашого ділового домену - може працювати, так що ви можете також оцінити його плюси і мінуси.
Пошук даних
«Присутній», «поточна» або «ефективна» версія Адреси виникнення повинна міститися у вигляді рядка в Address
таблиці, але вибір попередніх «станів» в адресу ВІД AddressHistory
(або з CustomerAddressHistory
таблиці) легко, і це може бути цікавою вправою для підвищення ваших навичок кодування SQL.
Що стосується однієї з ситуацій, про які ви згадували в коментарях, якщо ви хочете отримати "другу до останньої версії" окремого Address
рядка З неї AddressHistory
, ви повинні врахувати MAX(AddressHistory.AuditedDateTime)
те, AddressHistory.AddressId
що відповідає тому, яке саме Address.AddressId
значення має.
У зв'язку з цим - принаймні при створенні реляційної бази даних - досить зручно спочатку визначити відповідну концептуальну схему (виходячи з діючих правил бізнесу ) і після цього оголосити її подальше логічне розташування DDL. Після отримання стабільних і надійних версій цих основних елементів (які, звичайно, можуть розвиватися з часом), настав час проаналізувати та визначити найкращі способи маніпулювання (через операції INSERT, UPDATE, DELETE та SELECT або їх комбінації) щодо даних.
Сприйняття, погляди та допомога кінцевих користувачів допомога кінцевих користувачів
Очевидно, що на зовнішньому рівні абстрагування адресна інформація сприймається (кінцевими користувачами) як частина замовлення , і в цьому немає нічого поганого, але це не означає, що модельєрам доводиться проектувати значні частини база даних, про яку йдеться. З цього моменту, якщо є необхідність, наприклад, надрукувати "повне" замовлення (дуже можливо), ви можете "відтворити" його на вимогу за допомогою декількох підключення до операторів та пунктів WHERE (з огляду на термін дії тощо), можливо, зафіксовано у поданні про майбутнє споживання, надсилаючи відповідний набір результатів відповідним програмам, які, у свою чергу, можуть покращити його форматування за необхідності.
Звичайно, додаткові програми також будуть дуже корисними, коли виконується Замовлення ; наприклад, вікно настільних / мобільних додатків або веб-сторінка можуть:
- відображати лише Адреса (-и), яку залучений Клієнт визнав "корисною" (через
CustomerAddress.IsActive
);
- перерахуйте разом усі адреси, які Клієнт включив для отримання рахунків (через
CustomerAddress.IsBilling
); і
- згрупуйте всі адреси , визначені Замовником для послуги доставки (через
CustomerAddress.IsShipping
);
полегшення таким чином всіх залучених процесів у графічному інтерфейсі (тобто зовнішній рівень абстрагування комп'ютеризованої системи).
Пропоноване читання
Ви попросили (зараз видалені коментарі) деякі вказівки про звукову літературу бази даних; Тому, як і для теоретичного матеріалу, я настійно раджу вам прочитати всю роботу , написану доктором Е. Ф. Кодда , в премії Тьюринга одержувача і, звичайно ж , єдиним винуватцем у реляційної моделі даних (можливо , зараз більш актуальна , ніж коли - або). Цей список містить деякі його надзвичайно впливові статті та статті.
Дві важливі роботи, які не містяться у вищезгаданому списку, - це саме його лекція премії ACM Тюрінга під назвою " Реляційна база даних: Практичний фундамент продуктивності" від 1981 р. Та його книга "Реляційна модель управління базами даних: версія 2" , яка була опублікована в 1990 році.
На фронті концептуальної розробки інтегроване визначення інформаційного моделювання (IDEF1X) - це серйозно рекомендована методика, яка була визначена як стандарт у грудні 1993 р. Національним інститутом стандартів і технологій США (NIST).