我的表格LotTable
有PK= LotID, Name, rate
。
我有另一张LotTranslate
和PK=TranslateLotID
FK=MasterLotID
在插入LotTable
之前,我需要确保强制插入的PK
不是LotTranslate
中的PK。
我的问题是我做了一个触发器而不是插入或删除后?什么是最干净的方式,快速检查这个表并在LotTable
中停止插入,如果在LotTranslate
中找到PK?
我的方向我不确定这是否是正确的SQL Server方式......
CREATE TRIGGER tr_LotsInsert ON LotTable
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON
INSERT INTO dbo.LotTable
SELECT *
FROM INSERTED
WHERE INSERTED.LotID not in (select TranslateLotID from LotTranslate)
END
答案 0 :(得分:1)
我不建议使用触发器强制执行此操作。
您所描述的实际上是继承,其中不同的对象共享基本类型。在这种情况下,您具有Lot
(称为超类型)的基本概念,以及两个互斥的子类型,LotTable
和{{ 1}}。 (并且为了记录,我认为很遗憾您的数据库中有一个名为LotTranslate
的表,除非它实际上处理某些不是数据库对象的表。)
有一个相当完善的数据库设计模式来处理子类型和超类型:创建一个父表,在继承模式中用作“基础对象”,并使子类型表都与它有FK关系。要进一步强制执行互斥,您可以向所有表添加Table
列,并将其包含在外键中。
然后,您的基表以1对零或一对的关系参与两个表。到此处最重要的概念是Type
在所有表中始终相同,并且您不为任何表创建单独的代理键:base / supertype表包含子/中的相同值子类型表。
在我向您展示如何完成此操作之前,请允许我提一下,在这种情况下,您可以将两个表组合成一个表,并使用简单的LotID
列指示哪个表当然会阻止单一批次同时是两种类型。但是,我假设你的两个表之间有足够不同的列,这样做会大大浪费Type
值(如果只有几列不同,那么可能更好一些结合它们。)
NULL
请注意,您可能希望完成这项工作,以便将子表中的新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);
列放在LotTypeID
列之后,但这取决于您 - 只需要小心因为它需要表重新创建,如果你不了解并小心,你可能会损害你的数据库(先备份!)。
这种模式的一个巨大好处是不要错过在数据库中你想要FK到LotID
的任何地方,你可以选择使用其中一个子表或使用父表。这会限制您的其他表以允许其中一个或仅一个子类型。不容错过的另一个好处是,您可以将两个表之间的公共列放入父表中,而不是在子表中重复。最后,您可以为每个子项创建一个视图,该子视图公开组合的父+子列,就像原始子表一样。
最后,如果您继续使用触发器方法,则不必使用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
代替{ {1}}错过了一些关键的概念性学习,这些学习是在弄清楚如何将它们变成IN
的过程中继续进行的。还有其他一些实际的好处,例如嵌套的IN
查询得到了令人憎恶的事实难以理解和维护,同时再添加5个JOIN
s并不能在格式化时更难理解查询。