2011-05-20 33 views
9

我必須建立一個數據庫,並確保它是在一個特定的日期,我們可以加載數據,所以我決定用tuple versioning元組版本和複合主鍵

比方說,我們有以下兩個表:

CREATE TABLE Author 
(
    Id UNIQUEIDENTIFIER NOT NULL, 
    Firstname VARCHAR(100) NOT NULL, 
    Surname VARCHAR(200) NOT NULL, 
    ValidFrom DATETIME NOT NULL, 
    ValidUntil DATETIME NULL, 
    PRIMARY KEY (ID, ValidFrom) 
) 

CREATE TABLE Book 
(
    Id UNIQUEIDENTIFIER NOT NULL, 
    Title VARCHAR(100) NOT NULL, 
    ISBN VARCHAR(100) NOT NULL, 
    AuthorId UNIQUEIDENTIFIER NOT NULL, 
    ValidFrom DATETIME NOT NULL, 
    ValidUntil DATETIME NULL, 
    PRIMARY KEY (Id, ValidFrom) 
) 

的第一次,當我進入一個新的作者,我會生成一個新的GUID。我在書籍表中使用這個GUID以及作者的參考。

如果作者有更新,我創建一個具有相同GUID的新記錄,但將當前日期定義爲「ValidFrom」,並將原始記錄中的「ValidUntil」設置爲當前日期。

我沒有改變的書表,因爲Author.Id沒有改變。

我現在面臨的問題是,我想在Book.AuthorId = Author.Id

添加一個外鍵約束,不幸的是,這並不工作,因爲我使用的是複合主鍵。我不想將Author.ValidFrom添加到我的Book表中,因爲我只想引用最近的一個而不是特定的版本。

關於如何解決這個問題的任何想法?我想我可以添加一個觸發器,以確保在已經記錄了一本書的情況下不能刪除作者,但是我沒有解決方案來允許級聯刪除。

我爲每一個提示或提醒表示感謝。

+1

+1用於提及元組版本 – 2011-05-20 14:16:40

+1

您是否正在使用at最少的SQL Server 2008? – 2011-05-20 14:26:01

+2

梅根福克斯進行關係數據庫設計+1。 – Yuck 2011-05-20 14:47:41

回答

3

這個工程於2008年(依賴於使用MERGE語句來改變其行要被書引用原子)。它不引入新的列,你可能想隱藏視圖背後:

CREATE TABLE Author 
(
    Id UNIQUEIDENTIFIER NOT NULL, 
    Firstname VARCHAR(100) NOT NULL, 
    Surname VARCHAR(200) NOT NULL, 
    ValidFrom DATETIME NOT NULL, 
    ValidUntil DATETIME NULL, 
    Active as CASE WHEN ValidUntil is null THEN CONVERT(datetime,'99991231',112) ELSE ValidUntil END Persisted 
    PRIMARY KEY (ID, ValidFrom), 
    UNIQUE (ID,Active) 
) 
go 
CREATE TABLE Book 
(
    Id UNIQUEIDENTIFIER NOT NULL, 
    Title VARCHAR(100) NOT NULL, 
    ISBN VARCHAR(100) NOT NULL, 
    AuthorId UNIQUEIDENTIFIER NOT NULL, 
    ValidFrom DATETIME NOT NULL, 
    ValidUntil DATETIME NULL, 
    PRIMARY KEY (Id, ValidFrom), 
    FK_Link as CONVERT(datetime,'99991231',112) persisted, 
    Foreign key (AuthorID,FK_Link) references Author (Id,Active) on delete cascade 
) 
go 
declare @AuthorId uniqueidentifier 
set @AuthorId = NEWID() 
insert into Author(Id,Firstname,Surname,ValidFrom) 
select @AuthorId,'Boris','McBoris',CURRENT_TIMESTAMP 
insert into Book(Id,Title,ISBN,AuthorId,ValidFrom) 
select NEWID(),'How to use tuple versioning','12345678',@AuthorId,CURRENT_TIMESTAMP 

;with newAuthorInfo as (
    select @AuthorId as Id,'Steve' as Firstname,'McBoris' as Surname,t.Dupl 
    from (select 0 union all select 1) t(Dupl) 
) 
merge into Author a 
using newAuthorInfo nai 
on 
    a.Id = nai.Id and 
    a.ValidUntil is null and 
    nai.Dupl = 0 
when matched then update set ValidUntil = CURRENT_TIMESTAMP 
when not matched then insert (Id,Firstname,Surname,ValidFrom) 
values (nai.Id,nai.Firstname,nai.Surname,CURRENT_TIMESTAMP); 

;with newAuthorInfo as (
    select @AuthorId as Id,'Steve' as Firstname,'Sampson' as Surname,t.Dupl 
    from (select 0 union all select 1) t(Dupl) 
) 
merge into Author a 
using newAuthorInfo nai 
on 
    a.Id = nai.Id and 
    a.ValidUntil is null and 
    nai.Dupl = 0 
when matched then update set ValidUntil = CURRENT_TIMESTAMP 
when not matched then insert (Id,Firstname,Surname,ValidFrom) 
values (nai.Id,nai.Firstname,nai.Surname,CURRENT_TIMESTAMP); 

go 
select * from Author 
select * from Book 

delete from Author where ValidUntil is not null 

select * from Author 
select * from Book 

delete from Author 

select * from Author 
select * from Book 

對於2008年之前的解決方案,我不認爲你可以做得比觸發器更好。您可以引入第二個作者表,其中只包含Id列(唯一),您可以從Book中將FK反對,並從該表級聯刪除到Book。然後,您只需在作者上使用刪除觸發器,例如,如果您要刪除作者的特定作者ID的最後一行,請從此新表中刪除該行

+0

感謝您的建議,但我認爲即使使用SQL Server 2008也不會運行,因爲Author(ID,Active)上的UNIQUE CONSTRAINT僅在我們有一個或兩個版本的記錄時纔有效。隨着第三次更新,我們有兩個無效的和一個有效的記錄。 – MFox 2011-05-20 15:20:39

+0

@MFox - 我已經修復了它(並添加了第三個樣本行),因此它在2008年有效。我將不得不考慮2005年的解決方案。 – 2011-05-20 17:07:47