我在两个表之间有一个N:N关系,所以我有一个链接表来连接它们。此链接表的PK是两个表的两个PK的组合。这是基本的。
我想关联很多记录,所以在我的应用程序中我使用循环来创建我的命令:
begin transaction
insert into MyMiddleTable(ID1, ID2) VALUES(1, 2);
insert into MyMiddleTable(ID1, ID2) VALUES(1, 3);
...
commit;
但是如果我想要关联的其中一条记录在事务中间被其他进程删除,那么我会得到一个引用完整性的错误,这没关系,但是它不会创建任何其他关系可以创建,因为存在其他记录。
所以我的问题是,如果有一些方法可以告诉SQL Server这个引用完整性发生在一对寄存器中,忽略并继续下一个并创建可以创建的所有关系。因为如果一条记录因为删除而不存在,我不会创建这种关系,而是创建我想要的其他关系。
例如,当我尝试删除在进程中间删除的关系时,SQL Server会通知此事件,但继续并删除其余的关系。确实,在我的代码中,如果删除不在事务中,但我尝试在没有事务的情况下进行插入,问题仍然存在。
我知道其他解决方案可能会使用提示表阻止两个主表,但我想避免阻止两个表创建这种关系。
感谢。
答案 0 :(得分:1)
你无法将整件事包装在交易中:
开始交易
insert into MyMiddleTable(ID1, ID2) VALUES(1, 2);
insert into MyMiddleTable(ID1, ID2) VALUES(1, 3);
...
<德尔>提交; 德尔>
如果其中任何一个失败,您明确告诉SQL失败。当你说问题在不在事务中时仍然存在时,你从哪个程序执行这个SQL?如果您在SSMS中,您可能需要将每个语句与GO分开,否则您可能会获得包含所有语句的隐式事务。
答案 1 :(得分:1)
这里需要做的是删除该循环过程并处理基于集合的方法,以将记录作为一个事务的一部分提交到链接表。这里没有足够的信息来真正提供具体的逻辑,但这是一个例子。
请注意DISTINCT以防止重复插入和LEFT JOIN消除插入集中的现有值。
IF OBJECT_ID('LeftTable') IS NOT NULL DROP TABLE LeftTable
IF OBJECT_ID('RightTable') IS NOT NULL DROP TABLE RightTable
IF OBJECT_ID('BridgeTable') IS NOT NULL DROP TABLE BridgeTable
CREATE TABLE LeftTable (LeftID INT IDENTITY NOT NULL, LeftValue UNIQUEIDENTIFIER);
CREATE TABLE RightTable (RightID INT IDENTITY NOT NULL, RightValue UNIQUEIDENTIFIER);
CREATE TABLE BridgeTable (LeftID INT NOT NULL, RightID INT NOT NULL);
ALTER TABLE BridgeTable ADD CONSTRAINT [PK_BridgeTable_LeftIDRightID] PRIMARY KEY CLUSTERED ([LeftID], [RightID]);
WHILE (SELECT COUNT(*) FROM LeftTable) < 100
INSERT INTO LeftTable (LeftValue) SELECT NEWID()
WHILE (SELECT COUNT(*) FROM RightTable) < 100
INSERT INTO RightTable (RightValue) SELECT NEWID()
--Replace with actual matching logic
;WITH cteJoinSet AS (
SELECT DISTINCT L.LeftID, R.RightID
FROM LeftTable L
CROSS JOIN RightTable R
)
INSERT INTO BridgeTable (LeftID, RightID)
SELECT J.LeftID, J.RightID
FROM cteJoinSet J
LEFT JOIN BridgeTable B ON B.LeftID = J.LeftID
AND B.RightID = J.RightID
WHERE B.LeftID IS NULL