2009-11-27 106 views
0
我有問題拿出足夠的剋制在SQL Server 2005中我的問題涉及如下表

SQL Server的約束幫助

Table PKTable 
{ 
    pk integer primary key, 
    property integer, 
} 

Table FKTable 
{ 
    pk integer primary key, 
    fk integer references PKTable(pk), 
} 

我真的想使它不可能爲了一個記錄,fk_rec,當它引用的PKTable記錄擁有property = 5時,它就存在。我試圖做的第一件事是用下面的查詢創建一個模式綁定視圖,並在UniqueCol字段上創建一個唯一的索引。

SELECT  'True' AS UniqueCol, 'uh oh' AS DiffCol 
FROM   FKTable INNER JOIN 
         PKTable ON FKTable.fk = PKTable.pk 
WHERE  PKTable.property = 5 
UNION 
SELECT  'True' AS UniqueCol, 'default' AS DiffCol 

所以基本上,(「真」,「默認」)記錄將始終存在於視圖,當有人試圖將行插入FKTable和它引用的PKTable記錄具有屬性= 5,我因爲上面的聯合查詢的第一部分會返回一些東西,所以得到一個約束違規。無論如何,這是主意。但是,SQL Server 2005不允許在涉及聯合的視圖上使用索引。然後我試圖創建另一種觀點認爲:在這種情況下

SELECT UniqueCol, DiffCol FROM TheViewAbove 

上UniqueCol把唯一索引失敗,因爲你不能對引用另一個視圖的視圖索引。我知道這是一個長鏡頭。任何方式來解決這個問題?

謝謝!

回答

0

我真的不想更改表或所以在這裏表之間的關係是我做過什麼:

我創建了一個表中調用DummyTable在它超過1分的紀錄。我把2放在裏面。然後我建立了一個視圖:

SELECT pk FROM FKTable 
    INNER JOIN PKTable ON FKTable.fk = PKTable.pk 
    INNER JOIN DummyTable ON 1 = 1 
WHERE PKTable.property = 5 

然後,我在視圖中的pk字段上添加了一個唯一索引。這樣,當行存在違反我的約束時,我會得到重複。

2

兩種方式。

  1. 創建一個亞型表(說這就是所謂的NonProp5s,在它只有非財產= 5行,然後引用從FKTable而不是主PKTable這種亞型表的PK,這並不需要有什麼比它的PK列多,(Create Table NonProp5s (pk Integer Primary Key Not Null)關鍵是插入到母pkTable總是行插入NonProp5s,具有相同的PK值,除了其中屬性值等於5(你會還需要一個更新觸發插入/刪除行每當PKTable變化到/從5)
  2. 屬性值創建2個觸發器。一個上插入/更新到FK表THA如果您試圖插入一個引用PK行的記錄,並且屬性= 5,並且第二次觸發PK表的更新時,如果嘗試將屬性更改爲值= 5時回滾事務(如果存在任何子節點),則回滾事務記錄在FKTable中。
1
  1. 創建於PKTable唯一約束(PK,財產)
  2. 添加列PK_property到您的子表。有一個檢查約束保證(財產<> 5)
  3. 有一個外鍵參考(PK,pk_property)到PKTable(PK,財產)
+0

@Nitai - 這是行不通的。你是否正確地閱讀了這個問題? @Alex - 我可能最終會做你的建議。我之前做過,我不確定爲什麼我不想改變這裏的桌子。 – Jordan 2009-11-27 18:23:02

0

你也可以使用一個觸發器來實現的限制,像這樣:

首先創建表:

CREATE TABLE tPK(
ID int NOT NULL PRIMARY KEY 
,[Property] int NULL 
) 
go 

CREATE TABLE tFK(
ID int NOT NULL PRIMARY KEY 
,fk int NOT NULL 
) 
go 

ALTER TABLE tFK ADD 
CONSTRAINT FK1_tFK FOREIGN KEY(fk) REFERENCES tPK(ID) 
    ON UPDATE CASCADE 
    ON DELETE CASCADE 
go 

然後觸發添加到父表

CREATE TRIGGER trgPK ON tPK 
    AFTER INSERT, UPDATE 
AS 
IF UPDATE(Property) 
    BEGIN 
     DELETE FROM tFK 
     WHERE fk IN (SELECT T.ID 
         FROM tPK AS T 
         WHERE T.[Property] = 5) 

    END 
go 

而且在子表:

CREATE TRIGGER trgFK ON dbo.tFK 
    AFTER INSERT, UPDATE 
AS 
IF UPDATE(fk) 
    BEGIN 
     DELETE FROM tFK 
     WHERE fk IN (SELECT T.ID 
         FROM tPK AS T 
         WHERE T.[Property] = 5) 

    END 
GO 

如果你有大量裝載做,那麼:

  1. 禁用兩個觸發器,
  2. 負載數據,
  3. 同時啓用觸發器,
  4. 更新在任一表中的一行。