Konzeptionell gesehen sind Bestellung und Adresse in Ihrer Geschäftsumgebung zwar eng miteinander verbundene Ideen, es handelt sich jedoch tatsächlich um zwei separate Entitätstypen mit jeweils eigenen anwendbaren Eigenschaften (oder Attributen) und Einschränkungen.
Daher stimme ich, wie bereits in den Kommentaren erwähnt, @Erik zu , und Sie sollten das logische Layout Ihrer Datenbank unter folgenden Elementen organisieren:
- ein diskreter Tisch zu halten , Adressinformationsstücke;
- ein Tisch zu behalten Kunden -spezifische Details;
- ein Tisch zu umschließen Bestelldatenpunkten; und
- eine Tabelle mit Fakten zu den Zuordnungen zwischen Kunden und Adressen ;
wie ich weiter unten veranschaulichen werde.
Expository IDEF1X-Diagramm
Ein Bild sagt mehr als tausend Worte, deshalb habe ich das in Abbildung 1 gezeigte IDEF1X-Diagramm erstellt , um einige der Möglichkeiten zu veranschaulichen, die sich aus meinem Vorschlag ergeben:
Kunde , Adresse und deren Assoziationen
Wie gezeigt, habe ich eine Assoziation mit einem Viele-zu-Viele-Kardinalitätsverhältnis (M: N) zwischen den Entitätstypen Kunde a und Adresse dargestellt . Dieser Ansatz bietet künftige Flexibilität, da ein Kunde , wie Sie wissen, mehrere Adressen im Laufe der Zeit oder sogar gleichzeitig behalten kann und dieselbe Adresse von mehreren Kunden gemeinsam genutzt werden kann .
Eine bestimmte Adresse kann von mehreren Kunden (1: M) auf verschiedene Arten verwendet werden . Beispielsweise kann es als physisch definiert und / oder für den Versand und / oder die Abrechnung festgelegt werden . Möglicherweise kann dieselbe Adressinstanz gleichzeitig jedem der oben genannten Zwecke dienen, oder sie kann zwei Verwendungszwecke abdecken, während ein anderes Adressvorkommen den verbleibenden abdeckt.
a In einigen Geschäftsumgebungen kann ein Kunde entweder eine Person oder eine Organisation sein (Situation, die eine leicht unterschiedliche Anordnung implizieren würde, wie in dieser Antwort zu einer Supertyp-Subtyp-Struktur beschrieben), aber mit dem Ziel, ein vereinfachtes Beispiel bereitzustellen, habe ich mich entschieden diese Möglichkeit hier nicht einzuschließen. Falls Sie diese Situation in Ihrer Datenbank behandeln müssen, zeigt der Beitrag des vorherigen Links die Methode zur Lösung dieser Anforderung.
Reihenfolge , Adresse , Kundenadresse und Adressrollen
In der Regel sind für eine Bestellung nur zwei Arten von Adressen erforderlich , eine für den Versand und eine für die Abrechnung . Auf diese Weise kann dieselbe Adressinstanz beide Rollen für eine einzelne Bestellung ausfüllen , aber jede Rolle wird durch die jeweilige Eigenschaft dargestellt, dh ShippingAddressId oder BillingAddressId .
Die Bestellung wird mit der Adresse über den assoziativen Entitätstyp CustomerAddress mit Hilfe von zwei AUSLÄNDISCHEN SCHLÜSSELN mit mehreren Eigenschaften verbunden, d. H.
- ( CustomerNumber , ShippingAddressId ) und ( CustomerNumber , BillingAddressId ),
beide zeigen auf den PRIMARY KEY mit mehreren Eigenschaften von CustomerAddress , der als angezeigt wird
- ( Kundennummer , Adress-ID )
... was dazu beiträgt , eine Geschäftsregel zu vertreten , dass schreibt vor , dass (a) eine Bestell Instanz ausschließlich mit (b) verknüpft werden muß Adresse zuvor zugeordneten Ereignisse mit dem spezifischen Kunden , die das machte Auftrag , und nie mit (c) einem zufälligen nicht Kunden - verwandte Adresse .
Verlauf für (1) Adresse und für (2) die CustomerAddress- Zuordnung
Wenn Sie die Möglichkeit einer Änderung liefern wollen Adressinformationsstücke, dann müssen Sie den Überblick über alle Datenänderungen zu halten. Auf diese Weise habe ich Address als einen „überprüfbaren“ Entitätstyp dargestellt, der seine eigene AddressHistory verwaltet .
Da die Art einer Verbindung zwischen einem Kunden und einer Adresse auch eine oder mehrere Änderungen erfahren kann, habe ich auch die Möglichkeit dargestellt, eine solche Zuordnung aufgrund des Entitätstyps CustomerAddressHistory als „überprüfbar“ zu behandeln .
In dieser Hinsicht wurden verschiedene Faktoren behandelt, die in den Fragen und Antworten Nr. 1 und Q & A Nr. 2 , - sowohl über das Aktivieren zeitlicher Funktionen in einer Datenbank - sind wirklich relevant.
Illustratives logisches SQL-DDL-Layout
Infolgedessen habe ich in Bezug auf das oben gezeigte und erläuterte Diagramm die folgende Anordnung auf logischer Ebene deklariert (die Sie genau an Ihre Bedürfnisse anpassen können):
-- 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)
);
Wenn Sie einen Blick darauf werfen möchten, habe ich ihn in dieser Datenbank-Geige getestet , die unter SQL Server 2017 ausgeführt wird.
Die History
Tabellen
Der folgende Auszug aus Ihrer Frage ist sehr wichtig:
Was ich suche, ist, wie ich meine Adressen einrichten kann, damit die Bestellung beim Bearbeiten nicht durch die Tatsache beeinflusst wird, dass ein Kunde seine Adresse aktualisiert oder umzieht.
Die Tabellen AddressHistory
und CustomerAddressHistory
helfen dabei, sicherzustellen, dass eine Bestellung nicht von Adressänderungen betroffen ist , da alle „vorherigen“ Zeilen in der jeweiligen History
Tabelle beibehalten werden sollten und bei Bedarf abgefragt werden können. UPDATE- und DELETE-Operationen für diese beiden Tabellen sollten verboten sein (der Versuch, den Verlauf zu ändern, kann sogar negative rechtliche Auswirkungen haben).
Das Intervall umfasst die in eingeschlossenen Werte AddressHistory.CreatedDateTime
und AddressHistory.AuditedDateTime
steht für den gesamten Zeitraum, in dem eine bestimmte "vergangene" Address
Zeile als "gegenwärtig", "aktuell" oder "wirksam" eingestuft wurde. Ähnliche Überlegungen gelten für die CustomerAddressHistory
Zeilen.
Die CustomerAddress.IsActive
BIT-Spalte (Boolean) soll darauf hinweisen, ob eine bestimmte Address
Zeile von einer Customer
Zeile "verwendet" werden kann oder nicht. Wenn es beispielsweise auf "falsch" gesetzt ist, wird die Tatsache angezeigt, dass ein Kunde diese Adresse nicht mehr verwendet und sie daher nicht für neue Bestellungen verwendet werden kann .
Hinweis : Auf der anderen Seite habe ich einige Systeme gesehen , in dem jedes Mal, wenn ein neuer Auftrag , die bewirkt wird , Adressinformationen eingegeben wird (einige Male wiederholt) und die Adresse (n) für Vergangenheit Aufträge werden nie gelöscht (daher Die Bestellungen sind von Adressänderungen nicht betroffen .
Diese Vorgehensweise kann entschieden mit erheblichen Redundanzvolumina verbunden sein. Es besteht jedoch die Möglichkeit, dass - abhängig von den genauen Informationsanforderungen Ihrer Geschäftsdomäne - dies funktioniert. Daher möchten Sie möglicherweise auch die Vor- und Nachteile bewerten.
Datenabruf
Die „present“, „aktuelle“ oder „wirksam“ Version einer Adresse Auftreten muss als Zeile in der enthält seinen Address
Tisch, aber die Auswahl der vorherigen „Zustände“ eine Adresse aus der AddressHistory
(oder von CustomerAddressHistory
) Tabelle ist einfach und es kann Seien Sie eine interessante Übung, um Ihre SQL-Codierungsfähigkeiten zu verbessern.
In Bezug auf eine der Situationen, die Sie in den Kommentaren erwähnt haben, müssen Sie, wenn Sie die „vorletzte Version“ einer einzelnen Address
Zeile abrufen möchten, AddressHistory
die MAX(AddressHistory.AuditedDateTime)
und die berücksichtigen, die AddressHistory.AddressId
dem jeweiligen Address.AddressId
Wert entsprechen.
In dieser Hinsicht ist es - zumindest beim Erstellen einer relationalen Datenbank - sehr praktisch, zuerst das entsprechende konzeptionelle Schema (basierend auf den geltenden Geschäftsregeln ) zu definieren und anschließend die nachfolgende logische DDL-Anordnung zu deklarieren . Sobald Sie stabile und zuverlässige Versionen dieser grundlegenden Elemente erhalten haben (die sich natürlich im Laufe der Zeit weiterentwickeln können), ist es an der Zeit, die besten Manipulationsmöglichkeiten (über INSERT-, UPDATE-, DELETE- und SELECT-Operationen oder Kombinationen davon) zu analysieren und zu bestimmen zu Daten.
Unterstützung für Wahrnehmung, Ansichten und Anwendungsprogramme der Endbenutzer
Offensichtlich auf der äußeren Ebene der Abstraktion, Adresse wird Information (Endnutzer) wahrgenommen als Teil eines sein Auftrag , und es ist nichts einzuwenden, aber das bedeutet nicht , dass die Modellierer die wesentlichen Teile des entwerfen haben Datenbank in Frage so. Wenn in diesem Punkt beispielsweise eine „vollständige“ Bestellung gedruckt werden muss (sehr machbar), können Sie diese bei Bedarf mit Hilfe einiger JOIN-Operatoren und WHERE-Klauseln (unter Berücksichtigung der betreffenden Gültigkeitsdauer) „reproduzieren“ usw.) können in Ansichten für den zukünftigen Verbrauch festgelegt werden, indem die entsprechende Ergebnismenge an die zugehörigen Anwendungsprogramme gesendet wird, die wiederum die Formatierung nach Bedarf verbessern können.
Natürlich sind die Anwendungsprogramme auch sehr hilfreich, wenn ein Auftrag ausgeführt wird. Beispielsweise kann ein Desktop- / Mobile-App-Fenster oder eine Webseite:
- nur die Adresse (n) anzeigen , die der betroffene Kunde als "verwendbar" (über
CustomerAddress.IsActive
) festgelegt hat;
- Listen Sie alle Adressen auf , die der Kunde für den Abrechnungsservice aktiviert hat (via
CustomerAddress.IsBilling
). und
- Gruppieren Sie alle Adressen , die der Kunde für den Versandservice definiert hat (via
CustomerAddress.IsShipping
).
Erleichterung auf diese Weise aller beteiligten Prozesse auf der GUI (dh der externen Abstraktionsebene eines Computersystems).
Vorgeschlagene Literatur
Sie haben (in jetzt entfernten Kommentaren) einige Hinweise zur Sounddatenbankliteratur angefordert. In Bezug auf theoretisches Material empfehle ich daher dringend, dass Sie alle Arbeiten von Dr. EF Codd lesen , einem Turing- Preisträger und natürlich dem alleinigen Urheber des relationalen Datenmodells (vielleicht jetzt relevanter als je zuvor). Diese Liste enthält einige seiner äußerst einflussreichen Artikel und Artikel.
Zwei wichtige Werke, die nicht in der oben genannten Liste enthalten sind, sind genau sein ACM Turing Award Lecture mit dem Titel Relational Database: Eine praktische Grundlage für Produktivität von 1981 und sein Buch The Relational Model for Database Management: Version 2 , das veröffentlicht wurde in 1990.
In Bezug auf das Konzept ist die integrierte Definition für Informationsmodellierung (IDEF1X) eine ernsthaft empfehlenswerte Technik, die im Dezember 1993 vom US-amerikanischen National Institute of Standards and Technology (NIST) als Standard definiert wurde .