我一直在为在线商店设计一个数据库,我有一些与产品,零售商和订单相关的表格。我已经定义了一个触发器来阻止删除实际产品,而是将其标记为已删除,因为产品可能已经售出且客户可能已经付款。因此,如果我实际删除了产品,由于产品ID在所有其他表中被引用为外键,因此系统中可能会发生关于丢失订单,付款和财务数据的严重问题。因此,我已经做到了这一点:
INSTEAD OF DELETE
AS
DECLARE @id INT
SELECT @id = ProductId FROM deleted d
UPDATE Products SET Deleted = 1 WHERE ProductId = @id
BEGIN
SET NoCount ON
END
但是,这可能会大大增加表的大小,我想为数据库管理员提供实际在必要时删除数据的选项。由于我已创建此触发器,因此无法正常删除记录。我没有定义存储过程而不是这个的原因是,在这种情况下这个任务非常危险,但是,我正在寻找一种方法来定义一个特定的存储过程以允许摆脱整个必要时的数据。我想知道是否有任何方法强制删除记录,尽管已使用存储过程定义了此类触发器。我的意思是通过覆盖触发器。
答案 0 :(得分:1)
您应该使用外键约束来强制数据完整性。
另一方面,如果删除了多条记录,则此触发器失败。你应该把这个触发器写成像..
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON;
UPDATE Products
SET Deleted = 1
WHERE EXISTS (SELECT 1
FROM deleted
WHERE ProductId = Products.ProductId)
END
此外,如果要删除所有子记录,只需使用级联删除即可。这将删除引用表中的所有子记录。
如果由于某种原因您不想创建外键约束或删除级联,则唯一的选择是撤消此表的Delete
权限,然后创建存储过程并告诉用户使用该程序删除记录。
在该过程中,逐个删除所有表引用表中的所有子记录,然后最终从products表中删除。
对于想要物理删除记录的管理员,他们可以禁用触发器并运行删除命令,是的SQL Server具有使用以下命令禁用触发器的功能
DISABLE TRIGGER Tr_TriggerName ON dbo.Products;
GO
答案 1 :(得分:1)
您必须实现的最佳选择是开发一种受密码保护的触发器(确切地说不是受密码保护但类似的东西)。这可以使用Context_Info()
函数实现(或入侵)。它接受的值是二进制,因此您应该将所谓的密码转换为varbinary。例如:
INSTEAD OF DELETE
AS
DECLARE @id INT
SELECT @id = ProductId FROM deleted d
DECLARE @Pass VARBINARY(MAX)
SELECT @Pass = Context_Info()
IF @Pass = CAST('MY Password' AS VARBINARY(MAX))
BEGIN
-- Delete All The Tables Where Product ID Has Been Defined As FK --
END
ELSE
BEGIN
UPDATE Products SET Deleted = 1 WHERE ProductId = @id
END
BEGIN
SET NoCount ON
END
要使用密码,您可以这样做:
SET Context_Info CAST('MY Password' AS VARBINARY(MAX))
DELETE FROM Product WHERE ....