使用存储过程将记录从 SQL 服务器复制到 SQL 服务器 ( 2005)

Copy records using stored procedure from SQL Server to SQL Server ( 2005)

我有一个简单的存储过程 select,格式化记录并将记录从 TimeCard 数据库复制到我们的 ERP 数据库。两者都是 SQL 服务器。

它是 运行 在 SQL 服务器代理上作为计划作业。代码看起来像这样

INSERT INTO linked_erpserver.db.SCHEMA.table01 
SELECT * 
FROM   linked_timecardserver.db.SCHEMA.tablexx X 
WHERE  X.flag = 0 

UPDATE linked_timecardserver.db.SCHEMA.tablexx 
SET    flag = 1 
WHERE  flag = 0 

现在,假设如果有大量的记录并且连接到链接服务器失败,那将是灾难性的后果。

我该如何处理?我应该 select 一条一条地记录,插入,更新并提交那条记录。

编辑:我们正在使用 SQL Server 2005

使用分布式事务

您需要将您的代码包装在事务性(all/or 无)单元中。要支持此功能,需要安装 MSDTC 服务,运行,并可能在两个 Windows/SQL 服务器上进行配置。然后你需要使用 BEGIN DISTRIBUTED TRANSACTION T-SQL 语法。从 SQL Server 2005 开始,您拥有使用 XACT_STATE 的魔力,而我们过去只有 XACT_ABORT,它没有提供完整的解决方案(仅失败的严重级别为 16 或更高)。

XACT_STATE https://docs.microsoft.com/en-us/sql/t-sql/functions/xact-state-transact-sql

更新:这是 SQL 2005-2017 的代码:

SET XACT_ABORT ON
BEGIN DISTRIBUTED TRANSACTION;
INSERT INTO linked_erpserver.db.SCHEMA.table01 

SELECT * 
FROM   linked_timecardserver.db.SCHEMA.tablexx X 
WHERE  X.flag = 0 

UPDATE linked_timecardserver.db.SCHEMA.tablexx 
SET    flag = 1 
WHERE  flag = 0 

IF (XACT_STATE()) < 0 ROLLBACK TRANSACTION
--if XACT_STATE is 0, there is nothing to actually commit.
IF (XACT_STATE()) = 1 COMMIT TRANSACTION; 

这里有一个 link 显示如何获取 MS DTC 配置:

https://support.resolver.com/hc/en-ca/articles/207161116-Configure-Microsoft-Distributed-Transaction-Coordinator-MSDTC-

注: 显然,XACT_STATE 可以 return a -2 以及除以零错误之类的东西——因此上面代码中的 < 0 回滚。这似乎没有很好的记录,让我想知道实际上还有多少负值 XACT_STATE。

https://docs.microsoft.com/en-us/azure/sql-data-warehouse/sql-data-warehouse-develop-transactions

一条一条地插入记录总是被认为是一种不好的做法,但如果您在一条记录中插入数百万条记录,情况也是如此 select/insert。

我建议创建一个进程,一次插入 n 条记录,同时将所有内容包装在事务中,以确保在该步骤中更新所有记录,或者,如果错误,none 已更新。

DECLARE @NumRecords INT
SELECT @NumRecords=COUNT(*) FROM Linked_TimeCardServer.DB.Schema.TableXX X
WHERE X.FLAG = 0

WHILE @NumRecords > 0
BEGIN
    BEGIN TRAN

    -- Get 100 Records
    SET ROWCOUNT 100

    INSERT INTO Linked_ERPServer.DB.Schema.Table01
    SELECT * FROM Linked_TimeCardServer.DB.Schema.TableXX X
    WHERE X.FLAG = 0

    If @@error <> 0 GOTO Error

    -- Update the Records that were copied
    SET ROWCOUNT 0

    Update Linked_TimeCardServer.DB.Schema.TableXX
    SET FLAG =1
    WHERE PrimareyKeyColumnId NOT IN (
        SELECT PrimareyKeyColumnId FROM Linked_ERPServer.DB.Schema.Table01
    )

    If @@error <> 0 GOTO Error

    COMMIT TRAN

    SELECT @NumRecords=COUNT(*) FROM Linked_TimeCardServer.DB.Schema.TableXX X
    WHERE X.FLAG = 0

END

Error:
    ROLLBACK TRAN