假设我有两个声明如下的表变量:
DECLARE @Table1 TABLE (
A INT,
B NVARCHAR(100)
)
DECLARE @Table2 TABLE (
A INT,
C NVARCHAR(100)
)
这是@ Table1的内容:
1, 'Hello'
2, 'Hi'
3, 'Ola'
这些是@ Table2的内容:
1, 'my old friend'
1, 'sweetheart'
2, 'buddy'
4, 'the end'
现在,我想将@ Table1插入到表X中,并将@ Table2插入到表Y中。这种情况是,对于A列的每个相同值,我必须保持事务完整性以同时插入X和Y。
例如,假设我将@ Table1的第一行(1,'Hello')插入X。这意味着我还必须插入前两行((1,'my old friend'),(1 ,'sweetheart'))在同一事务中转换为Y。因此,如果Y的任何插入对于A = 1失败,那么X对于A = 1也会失败。对于同时不在@ Table1和@ Table2中的列A的任何值,它们本身都是单独的事务(例如,@ Table1中的A = 3和@ Table2中的A = 4)。
以下是我看到的解决此问题的方法:
我在@ Table1和@ Table2中都获取了A的所有值,在其上运行了一个游标,然后针对每个A的值,在单个事务中将它们插入到表X和Y中。首先,这里的问题是,我不想尽可能多地使用游标,而且这也意味着大量的单个插入。
我预先验证了@ Table1和@ Table2的值,然后对X上的@ Table1和Y上的@ Table2进行了一次插入。这将比上述方法快得多。但是我在这里看到的问题是,首先,不以某种方式将其放入“事务”中似乎并不正确,而且,我可能有一个很小的机会可能错过了某个地方的验证(不太可能,但仍然如此)。 / p>
我应该采用哪种方法?有更好的解决方案吗?
P.S。另请注意,如果只插入一个或几个A值时出现问题,我也不想使X和Y上的整个插入失败。此外,根据失败的插入回退并从数据库中删除表也是不希望的。这是一种选择,因为它会干扰正在运行的ID连续性,而我正努力避免这种情况。
答案 0 :(得分:0)
DML语句已完全执行或根本没有执行。
您可以同时使用两个选项
第一次添加尽可能多的验证,如果验证失败,则使用临时表而不是游标运行第二次验证
BEGIN TRY
BEGIN TRAN Opt2
--Option 2
COMMIT TRAN Opt2
END TRY
BEGIN CATCH
ROLLBACK TRAN Opt2
DECLARE @A INT, @B VARCHAR(100)
SELECT * INTO #TMP FROM @Table1
WHILE EXISTS (SELECT 1 FROM #TMP)
BEGIN
SELECT TOP 1 @A = A, @B = B FROM @Table1
-- Option 1
DELETE #Temp WHERE A = @A
END
END CATCH