2010-07-08 62 views
0

如果我有兩個表,說:SQL服務器/ TSQL更新表具有唯一約束

Clients 
(
    ClientID int primary key, 
    ClientName varchar(50) not null 
) 

Addresses 
(
    AddressID int primary key, 
    AddressLine1 varchar(50), 
    etc.. 
    ClientID int not null, 
    IsPrimaryAddress bit not null 
) 

跨越(ClientID, IsPrimaryAddress)唯一約束,怎麼能達到最新的表從代碼集合(而不是一個單一的SQL語句)沒有違反約束?

謝謝...

+3

你的收藏是什麼樣的?你如何將其轉移到SQL?這種限制的一個問題是,每個客戶端只能有2個地址(一個主要的,一個不是)。 – Oded 2010-07-08 08:22:12

+0

只是不要試圖插入任何違反約束條件的東西?!?!?我真的不明白你的問題,恐怕......你需要在這些表上更新什麼? – 2010-07-08 10:50:02

回答

2

這可能是一個錯誤都有一個唯一的約束跨(客戶端ID,IsPrimaryAddress),除非你想確保客戶可以有不超過兩個地址(一個主,一個等) ,因爲任何時候您嘗試添加更多非主地址都會違反完整性約束。

1

正如其他人已經提到的,這裏的問題似乎源於過度限制性的獨特約束。據推測,當你有一個客戶端的兩個地址並且想要交換主要的地址時,這會導致你很困難。在這種情況下,首先將主地址更新爲非主地址,並立即失敗,因爲同一客戶端的兩個非主地址違反了約束。

因此,該問題將通過僅在地址爲主時在ClientID上強制實施唯一約束來解決。這樣的conditional unique constraints之前已經討論過堆棧溢出。

如果你使用的是Oracle,那麼你可以聰明,做這樣的事情:

CREATE UNIQUE INDEX unique_primary_addr ON Addresses (
    DECODE (IsPrimaryAddress, 1, ClientId, NULL)); 

但是,我假設你使用的是SQL服務器或別的東西,所以你將被迫做這樣的事情:

CREATE FUNCTION PrimaryAddressCount(@Id INT) RETURNS INT AS 
BEGIN 
    DECLARE @ret INT; 
    SELECT @ret = COUNT(*) FROM Addresses WHERE ClientId = @Id AND IsPrimaryAddress = 1; 
    RETURN @ret; 
END; 
GO 

ALTER TABLE Addresses 
    ADD CONSTRAINT SinglePrimaryConstraint 
CHECK (IsPrimaryAddress != 1 OR dbo.PrimaryAddressCount(ClientId) = 1); 

無論哪種方式,所產生的約束將讓儘可能多的非主地址,你需要爲每個客戶端,但將執行一個主地址。這應該使您能夠輕鬆地更新地址,只要您始終最後寫入新的主地址即可。