如何为插入两个表的每个公用列值维护事务的完整性?

时间:2019-02-15 13:54:23

标签: sql sql-server

假设我有两个声明如下的表变量:

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)。

以下是我看到的解决此问题的方法:

  1. 我在@ Table1和@ Table2中都获取了A的所有值,在其上运行了一个游标,然后针对每个A的值,在单个事务中将它们插入到表X和Y中。首先,这里的问题是,我不想尽可能多地使用游标,而且这也意味着大量的单个插入。

  2. 我预先验证了@ Table1和@ Table2的值,然后对X上的@ Table1和Y上的@ Table2进行了一次插入。这将比上述方法快得多。但是我在这里看到的问题是,首先,不以某种方式将其放入“事务”中似乎并不正确,而且,我可能有一个很小的机会可能错过了某个地方的验证(不太可能,但仍然如此)。 / p>

我应该采用哪种方法?有更好的解决方案吗?

P.S。另请注意,如果只插入一个或几个A值时出现问题,我也不想使X和Y上的整个插入失败。此外,根据失败的插入回退并从数据库中删除表也是不希望的。这是一种选择,因为它会干扰正在运行的ID连续性,而我正努力避免这种情况。

1 个答案:

答案 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