使用存储过程将记录从 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 配置:
注:
显然,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
我有一个简单的存储过程 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 配置:
注: 显然,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