基础示例取自No way to use TSQL Output with normal foreign key constraints?;他的代码按预期失败了。但是,如果在示例中定义约束的方式修改如下,定义FK约束WITH NOCHECK
然后CHECK
,则OUTPUT INTO将无阻碍地运行。
这似乎与OUTPUT clause docs相矛盾。具体来说:
output_table [接收INTO的表格]不能:
•已启用在其上定义的触发器。
•参与FOREIGN KEY约束的任何一方 [强调添加]。
•具有CHECK约束或启用规则。
从关系角度来看,下面的可以工作,但应该特别排除此操作。如果将FK定义为直接“WITH CHECK”(默认值),则会按预期失败。如果它被定义为“WITH NOCHECK”,然后使用“CHECK CONSTRAINT”启用它,那么它就不会失败。
如果这是一个已知的支持功能,那将是非常棒的。或者我刚刚发现SQL中存在的错误至少是SQL 2008(我在2008年和2014年测试过)?为什么这样做?为什么不呢?使用它我有什么风险?
IF OBJECT_ID ('dbo.forn') IS NOT NULL
begin
alter table dbo.forn drop constraint FK_forn_prim
DROP TABLE dbo.forn;
end
IF OBJECT_ID ('dbo.prim') IS NOT NULL
DROP TABLE dbo.prim;
go
CREATE TABLE dbo.prim (c1 int PRIMARY KEY);
CREATE TABLE dbo.forn (c1 int );
alter table dbo.forn with nocheck add CONSTRAINT FK_forn_prim FOREIGN KEY (c1) REFERENCES dbo.prim(c1);
alter table dbo.forn check CONSTRAINT FK_forn_prim ;
go
-- does in fact fail with foreign key constraint violation
insert dbo.forn values (2);
-- works!!
INSERT INTO dbo.prim
OUTPUT inserted.c1 INTO dbo.forn
SELECT 1;
答案 0 :(得分:3)
在with check语句之后,系统仍然不信任外键。这是因为现有约束的默认值为WITH NOCHECK,因此您可以有效地运行:
alter table dbo.forn with nocheck check CONSTRAINT FK_forn_prim;
重新启用的正确语句是:
alter table dbo.forn with check check CONSTRAINT FK_forn_prim;
嵌套插入在运行后会再次失败。不建议让FK不受信任,因为SQL不会考虑许多操作。
您可以在系统视图sys.foreign_keys,is_not_trusted字段中检查不受信任的FK。
更多信息:https://sqlserverfast.com/blog/hugo/2007/03/can-you-trust-your-constraints/
答案 1 :(得分:0)
将您创建的值输出到第二个表中的语句可以正常工作,因为您的外键约束方向相反。内部语句依赖于外部语句,因此它将在另一个表中创建记录后执行。
只有在创建或更新记录dbo.forn时,SQL Server才会检查此外键。只要您在dbo.forn之前插入dbo.prim,您的代码就会执行。
使用:
INSERT INTO dbo.prim
OUTPUT inserted.c1 INTO dbo.forn
失败:
INSERT INTO dbo.forn
OUTPUT inserted.c1 INTO dbo.prim
<强> 编辑: 强>
微软可能会选择快速记录可能是一个相当复杂的场景,说你不应该期望它能够工作。我敢打赌,基于OUTPUT [INTO]列出的具有UPDATE和DELETE语句的细节,使用UPDATE或DELETE的类似尝试将失败。
{INSERT,UPDATE,DELETE} * {约束类型} * {列的类型} * {触发类型} * {无论我错过了什么}变成了大量的文档组合。
像往常一样,经验证据胜出,你的情景是可能的。
答案 2 :(得分:-1)
非常确定答案是隐式事务和约束检查是在事务结束时
IF OBJECT_ID ('dbo.forn') IS NOT NULL
begin
alter table dbo.forn drop constraint FK_forn_prim
DROP TABLE dbo.forn;
end
IF OBJECT_ID ('dbo.prim') IS NOT NULL
DROP TABLE dbo.prim;
go
CREATE TABLE dbo.prim (c1 int PRIMARY KEY);
CREATE TABLE dbo.forn (c1 int );
alter table dbo.forn with nocheck add CONSTRAINT FK_forn_prim FOREIGN KEY (c1) REFERENCES dbo.prim(c1);
alter table dbo.forn check CONSTRAINT FK_forn_prim ;
go
-- does in fact fail with foreign key constraint violation
insert dbo.forn values (1);
-- works!!
INSERT INTO dbo.prim
OUTPUT inserted.c1 INTO dbo.forn
SELECT 2;
-- does in fact fail with foreign key constraint violation
INSERT INTO dbo.prim
OUTPUT inserted.c1 + 1 INTO dbo.forn
SELECT 5;
select * from dbo.prim; -- 2 insert - it really did work
select * from dbo.forn; -- 2 insert - it really did work