Kavramsal olarak konuşursak, iş ortamınızda Düzen ve Adres , yakından ilişkili fikirler olsa da, aslında her biri kendi uygulanabilir özellik (veya öznitelikler) ve kısıtlamalara sahip iki ayrı varlık türüdür.
Bu nedenle, daha önce yorumlarda belirtildiği gibi, @Erik ile aynı fikirdeyim ve veritabanınızın mantıksal düzenini diğer öğeler arasında bildirerek düzenlemelisiniz:
- Adres bilgilerini tutmak için bir ayrı tablo ;
- Müşteriye özgü ayrıntıları korumak için bir tablo ;
- Sipariş veri noktalarını kapsayan bir tablo ; ve
- Müşteriler ve Adresler arasındaki ilişkiler hakkında gerçekleri içeren bir tablo ;
Aşağıda örnek olacağım gibi.
Açıklayıcı IDEF1X diyagramı
Bir resim bin kelimeye bedeldir, bu yüzden önerim tarafından açılan bazı olasılıkları göstermek için Şekil 1'de gösterilen IDEF1X diyagramını oluşturdum :
Müşteri , Adres ve ilişkilendirmeleri
Gösterildiği gibi, Müşteri a ve Adres varlık türleri arasında çoktan çoğa (M: N) bir kardinalite oranı ile bir ilişki tasvir ettim ; bu yaklaşım gelecekteki esnekliği sağlayacaktır çünkü bildiğiniz gibi bir Müşteri zaman içinde, hatta aynı anda birden fazla Adres tutabilir ve aynı Adres birden fazla Müşteri tarafından paylaşılabilir .
Belirli bir Adres , bire çok (1: M) Müşteriler tarafından çeşitli şekillerde kullanılabilir ; örneğin, Fiziksel olarak tanımlanabilir ve / veya Nakliye ve / veya Faturalandırma için ayarlanabilir . Belki de aynı Adres örneği, yukarıda belirtilen amaçların her birine aynı anda hizmet edebilir veya farklı bir Adres oluşumu geri kalanını kapsarken iki kullanımı kapsayabilir .
a Bazı iş ortamlarında, Müşteri ya bir Kişi ya da bir Kuruluş olabilir (bir süper tip-alt yapı hakkında bu cevapta ayrıntılı olarak açıklandığı gibi biraz farklı bir düzenleme anlamına gelir), ancak basitleştirilmiş bir örnek sunmak amacıyla karar verdim. bu olasılığı buraya dahil etmemek. Veritabanınızdaki bu durumu kapsamanız gerektiğinde, önceki bağlantının gönderisi söz konusu gereksinimi çözme yöntemini gösterir.
Sipariş , Adres , Müşteri Adresi ve Adres Rolleri
Genellikle, bir Sipariş yalnızca biri Nakliye ve diğeri Faturalandırma için olmak üzere iki tür Adres gerektirir . Bu şekilde, aynı Adres örneği ayrı bir Sipariş için her iki Rolü de doldurabilir , ancak her bir Rol ilgili özellik, yani ShippingAddressId veya BillingAddressId tarafından resmedilir .
Sipariş ile bağlı Adres aracılığı CustomerAddress , yani iki çoklu mülkiyet yabancı anahtarlar, yardımıyla ilişkisel varlık türü
- ( CustomerNumber , ShippingAddressId ) ve ( CustomerNumber , BillingAddressId ),
her ikisi de gösterilen CustomerAddress çok özellikli PRIMARY KEY
- ( CustomerNumber , AddressId )
... öngörmektedir ki (a) bir bir iş kuralını temsil etmek yardımcı olur Sipariş örneği (b) ile münhasıran bağlantılı olmalıdır Adres oluşumları önceden belirli ilişkili Müşteri yaptığı Sipariş ve asla rastgele olmayan (c) Müşteri - ilgili Adres .
Geçmiş (1) için adres ve (2) için CustomerAddress birlikte
Adres bilgilerinin değiştirilme olasılığını sağlamak istiyorsanız, tüm veri değişikliklerini takip etmeniz gerekir. Bu şekilde, Adres'i kendi AddressHistory özelliğini koruyan “denetlenebilir” varlık türü olarak tasvir ettim .
Bir Müşteri ile Adres arasındaki bağlantının niteliği de bir veya daha fazla değişikliğe uğrayabileceğinden, CustomerAddressHistory varlık türü sayesinde “denetlenebilir” bir ilişkiyi yönetme olasılığını da gösterdim .
Bu bağlamda, Soru-Cevap no. 1 ve Soru-Cevap no. 2 , —Bir veritabanında zamansal yeteneklerin etkinleştirilmesine dair her ikisi de - gerçekten önemlidir.
Açıklayıcı SQL-DDL mantıksal düzeni
Sonuç olarak, yukarıda gösterilen ve açıklanan diyagram açısından, aşağıdaki mantıksal seviye düzenlemesini beyan ettim (ihtiyaçlarınızı tam olarak karşılayacak şekilde uyarlayabilirsiniz):
-- 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)
);
Bir göz atmak istiyorsanız , SQL Server 2017'de çalışan bu db <> kemanında test ettim .
History
tablolar
Sorunuzdan aşağıdaki alıntı çok önemlidir:
Aradığım şey, adreslerimi nasıl ayarlayabileceğim, böylece onları düzenlediğimde, sipariş bir müşterinin adresini güncellemesi veya yerini değiştirmesinden etkilenmez.
AddressHistory
Ve CustomerAddressHistory
bir sağlamada tabloları yardım al etkilenmez Adres bütün “önceki” satırları, ilgili saklanacaktır gerektiği gibi, değişiklikleri History
masaya ve gerektiğinde sorular sorulabilir. Bu iki tablodaki GÜNCELLEME ve SİL işlemlerinin yasaklanması gerekir (geçmişi değiştirmeye çalışmanın olumsuz yasal sonuçları bile olabilir).
Aralık içinde yer alan değerleri arasında kapsanan AddressHistory.CreatedDateTime
ve AddressHistory.AuditedDateTime
tüm temsil Dönem belirli bir “son” sırasında Address
satır, “geçerli” veya “etkili” “mevcut” kabul edildi. Benzer düşünceler CustomerAddressHistory
satırlar için de geçerlidir .
CustomerAddress.IsActive
BİT (boolean) sütunu belirli bir olmadığını işaret etmek anlamına gelir Address
satır tarafından “kullanılabilir” bir Customer
satır ya da; örneğin, 'yanlış' olarak ayarlanırsa, bir Müşterinin bu Adresi artık kullanmadığını ve dolayısıyla yeni Siparişler için kullanılamayacağını bildirir .
Not : Öte yandan, her yeni Sipariş verildiğinde Adres bilgilerinin girilmesi gereken (bazen tekrar tekrar) ve geçmiş Siparişler için kullanılan Adres (ler) in asla silinmediği bazı sistemler gördüm. Siparişleri etkilenmez Adres ) değişiklikleri.
Bu eylem süreci kesinlikle önemli miktarda yedeklilik içerebilir, ancak iş alanınızın kesin bilgi gereksinimlerine bağlı olarak işe yarayabilir, bu nedenle artılarını ve eksilerini de değerlendirmek isteyebilirsiniz.
Veri alma
Bir arasında “mevcut”, “geçerli” veya “etkili” versiyonu Adres bir oluşum içinde, bir satır olarak bulunması gereken Address
tablo, ancak bir önceki “durumları”, seçme Adres DAN AddressHistory
(veya CustomerAddressHistory
) Tablo kolaydır, ve bunu, SQL kodlama becerilerinizi geliştirmek için ilginç bir egzersiz yapın.
Eğer bir birey “son sürümüne ikinci” almak istiyorsanız, yorum olarak bahsedilen bu durumlardan biri ile ilgili olarak Address
onun GELEN satırda AddressHistory
, dikkate almak zorunda MAX(AddressHistory.AuditedDateTime)
ve AddressHistory.AddressId
özellikle aynı olduğundan Address.AddressId
el altında değer.
Bu bakımdan - en azından ilişkisel bir veritabanı oluşturulurken - önce ilgili kavramsal şemayı tanımlamak (geçerli iş kurallarına dayalı olarak ) ve daha sonra sonraki mantıksal DDL düzenlemesini beyan etmek oldukça uygundur . Bu temel öğelerin kararlı ve güvenilir sürümlerini elde ettikten sonra (elbette zamanla gelişebilir), manipüle etmenin en iyi yollarını analiz etme ve belirleme zamanıdır (INSERT, UPDATE, DELETE ve SELECT işlemleri veya bunların kombinasyonları aracılığıyla) ilgili veriler.
Son kullanıcıların algılama, görüntüleme ve uygulama programı yardımı
Açıkça görüldüğü gibi , dış soyutlama düzeyinde, Adres bilgileri (son kullanıcılar tarafından) bir Siparişin parçası olarak algılanır ve bununla ilgili yanlış bir şey yoktur, ancak bu, modelcilerin söz konusu veritabanı. Bu noktada, örneğin, “tam” bir Sipariş (çok uygun) yazdırmaya ihtiyaç varsa, birkaç JOIN operatörünün ve WHERE yan tümcelerinin yardımıyla (talep geçerlilik süresi göz önünde bulundurularak) talep üzerine “yeniden” oluşturabilirsiniz. , vb.) gelecekteki tüketim görünümlerinde düzeltilebilir , ilgili sonuç kümesini ilgili uygulama programlarına gönderir ve bu da biçimlendirmesini gerektiği gibi geliştirebilir.
Tabii ki, uygulama programı (ler) bir çok zaman çok yararlı olacaktır al yürürlüğe ediliyor; örneğin, bir masaüstü / mobil uygulama penceresi veya bir web sayfası şunları yapabilir:
- yalnızca ilgili Müşterinin “kullanılabilir” (üzerinden ) olarak belirlediği Adresleri görüntüler ;
CustomerAddress.IsActive
- Liste hep birlikte Adresleri o Müşteri (yoluyla fatura servisi için sağladı
CustomerAddress.IsBilling
); ve
- grup hepsi Adresleri o Müşteri (aracılığıyla hizmet nakliye için tanımladığı
CustomerAddress.IsShipping
);
bu şekilde GUI'deki tüm ilgili süreçleri kolaylaştırmak (yani bilgisayarlı bir sistemin dış soyutlama seviyesi).
Önerilen Okuma
Sağlam veritabanı literatürü hakkında bazı işaretçiler istediniz (şimdi kaldırıldı yorumlarında); bu nedenle, teorik materyale gelince , Turing Ödülü sahibi Dr. EF Codd ve elbette ilişkisel veri modelinin tek yaratıcısı olan (belki şimdi her zamankinden daha alakalı) Dr. Bu liste , muazzam derecede etkili makalelerini ve makalelerini içermektedir.
Yukarıda adı geçen listede yer almayan iki önemli eser, tam olarak, İlişkisel Veritabanı başlıklı ACM Turing Ödülü Konferansı : 1981'den itibaren Verimlilik için Pratik Bir Temel ve kitabının Veri Tabanı Yönetimi için İlişkisel Model: Sürüm 2 olarak adlandırdığı 1990 yılında.
Açık kavramsal tasarım ön, Bilgi Sistemi için Entegre Tanımı (IDEF1X) ABD tarafından Aralık 1993 yılında bir standart olarak tanımlandı ciddi tavsiye tekniktir Ulusal Standartlar ve Teknoloji Enstitüsü (NIST).