无法使用带有普通外键约束的TSQL输出?
以下代码段失败,出现错误: OUTPUT INTO子句的目标表“dbo.forn”不能位于主键和外键关系的任一侧。找到引用约束“FK\u forn\u prim” 我只能通过禁用外键约束来使用输出?如何做到这一点无法使用带有普通外键约束的TSQL输出?,tsql,Tsql,以下代码段失败,出现错误: OUTPUT INTO子句的目标表“dbo.forn”不能位于主键和外键关系的任一侧。找到引用约束“FK\u forn\u prim” 我只能通过禁用外键约束来使用输出?如何做到这一点 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 ('d
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 CONSTRAINT FK_forn_prim FOREIGN KEY (c1) REFERENCES dbo.prim(c1));
go
INSERT INTO dbo.prim
OUTPUT inserted.c1 INTO dbo.forn
SELECT 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 CONSTRAINT FK_forn_prim FOREIGN KEY (c1) REFERENCES dbo.prim(c1));
go
CREATE TRIGGER InsertRecord
ON dbo.Prim
AFTER Insert
AS
BEGIN
SET NOCOUNT ON;
Insert into dbo.forn Select * from inserted;
END
GO
INSERT INTO dbo.prim SELECT 1;
通常输出到一个表变量或临时表,然后使用该变量插入到最终的表。没错,在外键约束下,输出语句在表上不起作用 另一个选项是在插入数据时临时禁用约束。虽然这不应该成为标准,但对于一次性加载的数据,它工作得很好
ALTER TABLE dbo.forn
NOCHECK CONSTRAINT FK_forn_prim
GO
INSERT INTO dbo.prim
OUTPUT inserted.c1 INTO dbo.forn
SELECT 1;
ALTER TABLE dbo.forn
CHECK CONSTRAINT FK_forn_prim
GO
文档确实指出,输出表可能不参与外键约束或检查约束,也可能未启用定义在其上的触发器,但此处不考虑这些情况。Msg 332错误就是这种情况的表现 不建议这样做。请参阅下面的更新 但是,我发现,如果禁用外键约束并使用NOCHECK/CHECK重新启用该约束,即使在重新启用该约束之后,该限制也会被破坏。换言之:一个禁用启用循环足以使FK约束对输出不可见,并转化为外键约束禁止。请注意以下修改:
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);
-- note change here:
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 ;
-- end change
go
INSERT INTO dbo.prim
OUTPUT inserted.c1 INTO dbo.forn
select 1;
以下约束冲突失败,因此您知道DRI仍在工作:
INSERT INTO dbo.prim
OUTPUT inserted.c1 + 1 INTO dbo.forn
select 2;
鉴于文件中的禁令,我承认这似乎是可疑的。在这一点上我有一个悬而未决的问题,尽管它没有得到很好的回应
使现代化
前面提到的问题是,新的信息使这个答案无效。将此作为对其他人的警告,以防他们偶然发现这个看似偶然的漏洞
结果是:改变表dbo.forn check约束FK\u forn\u prim;可重新启用约束,但使其处于不受信任的状态,因此SQL引擎无法充分利用它进行索引优化等。不建议这样做。重新启用的正确方法是
alter table dbo.forn with check check CONSTRAINT FK_forn_prim;
使用insert into表变量 声明@HISTORY\u扩展表 历史\u ID INT不为空, 编号NVARCHAR50不为空 -离开 插入[dbo].[HISTORY] [守则] ,[邮票] 插入输出。Id,日期 进入@HISTORY\u扩展 [历史编号] ,[编号] 选择 1. 日期 从交易
其中DATE='2021-05-20'那么,这个片段就是为了说明这个问题;我有正常的桌子,但触发器不起作用。我必须禁用约束。非常有趣,尽管这种方法可能不被推荐。当然不是。你的评论让我想起了这一点,我现在更清楚了。希望这不会误导很多人。你能举个例子吗?