我不推薦使用觸發器強制執行這一點。
你所描述的實際上是繼承,其中不同的對象共享一個基類型。在這種情況下,您的基本概念是Lot
(稱爲超類型),以及兩個互斥,LotTable
和LotTranslate
的子類型。 (爲了記錄,我認爲不幸的是,你的數據庫有一個名字爲Table
的表格,除非它實際處理某種非數據庫對象的表格)。
有一個合理建立的數據庫設計模式來處理子類型和超類型:創建一個用作繼承模式中的「基礎對象」的父表,並使子類型表都具有FK關係它。要額外執行相互排他性,您可以將Type
列添加到所有表中並將其包含在外鍵中。
然後,您的基表以1到0或1的關係參與兩個表。最重要的概念是LotID
在所有表中始終相同,並且您不爲任何表創建單獨的代理鍵:基類/超類型表包含與子/子類型表中相同的值。
在我告訴你如何做到這一點之前,讓我提一下,在這種情況下,可能你的兩個表格應該被合併爲一個表格,並且有一個簡單的Type
列表明哪一個當然會阻止單個Lot一次是兩種類型。然而,我假設你的兩個表有足夠多的列,它們之間會有很大的差別,這樣做會造成很大的浪費(如果只有幾列不同,最好將它們組合起來)。你可能想要做的工作,以獲得在子表的新LotTypeID
列
CREATE TABLE dbo.LotBase (
LotID int NOT NULL CONSTRAINT PK_LotBase PRIMARY KEY CLUSTERED,
LotTypeID tinyint NOT NULL
CONSTRAINT FK_LotBase_LotTypeID FOREIGN KEY
REFERENCES dbo.LotType (LotTypeID),
-- A unique constraint needed for FK purposes
CONSTRAINT UQ_LotBase_LotID_LotTypeID
UNIQUE (LotID, LotTypeID)
);
-- Include script here to create a LotType table and populate it with two rows
-- 1 = `Standard Lot` and 2 = `TranslateLot`
INSERT dbo.LotBase (LotID, LotTypeID)
SELECT LotID, 1
FROM dbo.LotTable;
INSERT dbo.LotBase (LotID, LotTypeID)
SELECT TranslateLotID, 2
FROM dbo.LotTranslate;
ALTER TABLE dbo.LotTable ADD LotTypeID tinyint NOT NULL
CONSTRAINT DF_LotTable_LotTypeID DEFAULT (1);
ALTER TABLE dbo.LotTranslate ADD LotTypeID tinyint NOT NULL
CONSTRAINT DF_LotTranslate_LotTypeID DEFAULT (2);
ALTER TABLE dbo.LotTable ADD CONSTRAINT FK_LotTable_LotBase
FOREIGN KEY (LotID, LotTypeID)
REFERENCES dbo.LotBase (LotID, LotTypeID);
ALTER TABLE dbo.LotTable ADD CONSTRAINT FK_LotTable_LotBase
FOREIGN KEY (LotID, LotTypeID)
REFERENCES dbo.LotBase (LotID, LotTypeID);
注立即向LotID
列之後位於,但它是由你 - 只是要小心,因爲它需要表娛樂,如果你不熟悉和小心,你可能會傷害你的數據庫(先備份!)。
這種模式不會錯過的一個巨大好處是,在數據庫的任何地方你想要FK到Lot
,你可以選擇使用其中一個子表或使用父表。這限制了你的其他表,以允許兩種或只有一種子類型。不要錯過的另一個好處是,您可以將兩個表格之間的公共列放入父表格中,而不是在兒童中重複。最後,您可以爲每個展示組合父+子列的子視圖創建一個視圖,就像原始子視圖一樣。
最後,如果您堅持繼續使用觸發器方法,則不必使用INSTEAD OF
觸發器。你可以ROLLBACK
這是不恰當的交易:
CREATE TRIGGER TR_LotTable_I ON dbo.LotTable FOR INSERT
AS
SET NOCOUNT ON;
SET XACT_ABORT ON;
IF EXISTS (
SELECT *
FROM
Inserted I
INNER JOIN dbo.LotTranslate LT
ON I.LotID = LT.TranslateLotID
) ROLLBACK TRAN;
這是一個更好的方法來處理它(的一件事,你就不必每次都修改它,你一列添加到您的LotTable
表。另外,我建議你學會使用(然後一貫地使用)JOIN
語法,而不是你展示的IN
語法。雖然我對這個建議有一些爭議,但根據我的經驗,使用IN
而不是JOIN
s錯過了一些重要的概念性學習,這些概念性學習繼續研究如何使它們變成JOIN
s。還有其他實際益處,例如嵌套IN
查詢會變得非常難以理解和維護,而添加5個以上的JOIN
當格式良好時,並不會使查詢變得難以理解。
謝謝埃裏克 - 我無法實現更大的解決方案這個表實際上沒有名稱中的TABLE,lotTranslate是一個很小的表格補丁來管理導致這個混亂的電話號碼的一些路由,所以你的觸發器工作像一個魅力。我瞭解IN,但加入對此很好,並且所有這些表格都進行了重新設計,因此這是一個臨時補丁,並且您的觸發器在幾個月內完美無缺,可以防止插入錯誤。 –