Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Server:替代触发器是否会影响引用完整性检查?_Sql_Sql Server_Sql Server 2005_Tsql_Triggers - Fatal编程技术网

SQL Server:替代触发器是否会影响引用完整性检查?

SQL Server:替代触发器是否会影响引用完整性检查?,sql,sql-server,sql-server-2005,tsql,triggers,Sql,Sql Server,Sql Server 2005,Tsql,Triggers,如果外键引用的内容不存在,我想将其设置为null。但是,我希望所有其他引用完整性检查都能正常工作 一个而不是触发器会迫使我写所有完整性检查吗 由于触发器无法更改插入的表,并且由于引用完整性,数据不能存在于目标表中,因此是否有方法将这些外键设为null,以便记录可以保存 编辑:我犯的最大错误是不知道如果存在而不是触发器,数据库将不会进行任何更改。触发器必须对表本身进行更改。如果外键可为NULL,则可以使用DELETE SET NULL上的,在删除引用行时将外键更新为NULL ON DELETE S

如果外键引用的内容不存在,我想将其设置为null。但是,我希望所有其他引用完整性检查都能正常工作

一个
而不是
触发器会迫使我写所有完整性检查吗

由于触发器无法更改插入的表,并且由于引用完整性,数据不能存在于目标表中,因此是否有方法将这些外键设为null,以便记录可以保存


编辑:我犯的最大错误是不知道如果存在
而不是
触发器,数据库将不会进行任何更改。触发器必须对表本身进行更改。

如果外键可为NULL,则可以使用DELETE SET NULL上的
在删除引用行时将外键更新为NULL


ON DELETE SET DEFAULT
是另一种可能性,具体取决于您的应用程序。

正如@Catcall所指出的那样,ON DELETE SET NULL
引用操作实现了您想要的功能

也就是说,您可以编写一个
而不是
触发器来执行相同的操作(或主题的变体),而无需自己考虑所有引用完整性约束。下面是一个简单的例子:

表和测试数据:

CREATE TABLE T1 (ID INTEGER NOT NULL UNIQUE);
CREATE TABLE T2 (ID INTEGER REFERENCES T1 (ID));

INSERT INTO T1 VALUES (1), (2), (3);
INSERT INTO T2 VALUES (1), (2), (3), (2), (3), (3);
触发因素:

-- 'CREATE TRIGGER' must be the first statement in a batch.
CREATE TRIGGER tr__T1__instead_of_delete
ON T1
INSTEAD OF DELETE
AS
BEGIN;

UPDATE T2
   SET ID = NULL
 WHERE EXISTS (
               SELECT * 
                  FROM deleted
                 WHERE deleted.ID = T2.ID
              );

DELETE
  FROM T1
 WHERE EXISTS (
               SELECT * 
                  FROM deleted
                 WHERE deleted.ID = T1.ID
              );

END;
DELETE 
  FROM T1 
 WHERE ID = 3;
测试触发器:

-- 'CREATE TRIGGER' must be the first statement in a batch.
CREATE TRIGGER tr__T1__instead_of_delete
ON T1
INSTEAD OF DELETE
AS
BEGIN;

UPDATE T2
   SET ID = NULL
 WHERE EXISTS (
               SELECT * 
                  FROM deleted
                 WHERE deleted.ID = T2.ID
              );

DELETE
  FROM T1
 WHERE EXISTS (
               SELECT * 
                  FROM deleted
                 WHERE deleted.ID = T1.ID
              );

END;
DELETE 
  FROM T1 
 WHERE ID = 3;

存在不涉及删除(可能有价值的)数据的方法。为什么要在订单记录中将CustomerID字段设置为NULL,只是为了保存订单记录?在Customers表中为所有不存在的order.customerid创建虚拟记录不是更好吗?这将允许保存订单记录,同时保留要删除的数据,以便保存记录。如果客户表中不存在order.customerid,那么首先如何建立外键约束?鸡和蛋问题:一个用户创建一个产品列表,然后另一个用户获得一个产品列表。在第二个用户保存其引用之前,第一个用户删除了这些产品。我们希望保存第二个,但不希望引用缺少的产品。如果不希望保存没有有效引用的记录,则希望返回错误。牺牲数据完整性是个坏主意。如果产品已不存在,则需要通知用户2。@Zim博士:用户A选择产品,然后用户B选择产品,然后用户A删除其中一些产品,这样用户B的列表就不再是最新的,当用户B插入(比如)订单记录时,引用其中一个已删除的产品,RI约束导致用户B的插入失败?@Tim,A创建产品,B使用产品,但同时A删除了产品。B需要保存记录,以便在目标不存在时FKs为空。在组装B记录期间,B不能“重新加载”A记录,但可以重新加载B记录以查看缺少的引用并修复它们。B可能不是修理它们的同一个人。我们曾考虑放弃ref完整性,但在我们的案例中,引用不存在的产品比什么都不引用更糟糕。这略有不同。如果一个人创建了一个产品,然后另一个人尝试引用该产品,但在他们保存之前,第一个人删除了该产品,我们希望第二个人使用空值保存该产品(第二个人保存时该产品不存在以引用该产品)。在您的示例中,第二个人似乎成功保存,然后,当产品删除时,引用被设置为null。您可以通过打开两个shell来测试COMMIT语句是如何工作的。我不确定我是否理解您的担忧,因为两种情况的最终结果都是相同的——一个NULL而不是一个值。例如,在PostgreSQL中,DELETE语句在之前启动的INSERT提交之前不会提交。问题是第二条记录不会保存,因为第一条记录不存在。但是,我没有注意到,如果出现
而不是
触发器,会关闭正常的数据持久性,让触发器本身执行实际的插入/更新命令。@Zim博士:这是基于您对事务的理解,还是基于实际测试?您似乎在说,本质上,在INSERT之后启动的DELETE语句总是在INSERT语句之前提交。我没有在这里运行SQL Server实例,但我不确定您的说法是否正确。+1表示在存在instead of触发器时不必检查引用。现在,如果在数据更改之前运行
而不是
,并且插入和删除的视图是只读的,那么如何更正要保存的数据,以便将坏外键设置为null?在触发器触发时,目标表中是否存在此无效记录,并在触发器执行后使事务失败,从而删除该记录?我刚刚想到,如果
而不是
触发器没有执行任何操作,则不会更改任何记录。LOL.所以你的答案就是答案,就像你的例子中那样,在前面使用插入/更新而不是触发器来清空值。