MSSQL跨数据库访问:从远程服务器同步人员数据
今天我们来学习如何在SQL Server中跨数据库访问数据,实现不同服务器之间的数据同步。
CREATE PROCEDURE usp_SyncPersonnelDataASBEGIN SET NOCOUNT ON BEGIN TRY BEGIN TRANSACTION -- 1. 创建临时表存放远程数据 SELECT CAST(工号 AS INT) AS PersonNo, 姓名 AS PersonName, 直间接 AS DutyType INTO #TempPersonnel FROM OPENDATASOURCE( 'SQLOLEDB', 'DATA SOURCE=DATABAK;UID=sa;PWD=密码;' ).gwidb.dbo.out_TANXUEMEISYSTEMpawf -- 2. 处理离职人员(更新状态为离职) UPDATE dp SET Workflag = 'N' FROM syteline.SHATDB.dbo.DeptPerson dp LEFT JOIN #TempPersonnel tp ON dp.PersonNo = tp.PersonNo WHERE tp.PersonNo IS NULL -- 在远程表中不存在 = 已离职 AND dp.Workflag = 'Y' -- 只处理在职的 -- 3. 处理在职人员(存在则更新,不存在则新增) -- 3.1 更新已存在人员 UPDATE dp SET PersonNo = tp.PersonNo, [Name] = tp.PersonName, Duty = tp.DutyType, Workflag = 'Y' FROM syteline.SHATDB.dbo.DeptPerson dp INNER JOIN #TempPersonnel tp ON dp.PersonNo = tp.PersonNo -- 3.2 新增不存在人员 INSERT INTO syteline.SHATDB.dbo.DeptPerson ( PersonNo, [Name], Workflag, Duty ) SELECT tp.PersonNo, tp.PersonName, 'Y', tp.DutyType FROM #TempPersonnel tp WHERE NOT EXISTS ( SELECT 1 FROM syteline.SHATDB.dbo.DeptPerson dp WHERE dp.PersonNo = tp.PersonNo ) -- 清理临时表 DROP TABLE #TempPersonnel COMMIT TRANSACTION PRINT '人员数据同步完成' END TRY BEGIN CATCH ROLLBACK TRANSACTION DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE() DECLARE @ErrorSeverity INT = ERROR_SEVERITY() RAISERROR(@ErrorMessage, @ErrorSeverity, 1) END CATCHEND
-- 1. 首先创建链接服务器(只需执行一次)EXEC sp_addlinkedserver @server = 'RemoteHR', -- 链接服务器名称 @srvproduct = '', @provider = 'SQLOLEDB', @datasrc = 'DATABAK' -- 远程服务器地址EXEC sp_addlinkedsrvlogin @rmtsrvname = 'RemoteHR', @useself = 'false', @rmtuser = 'sa', @rmtpassword = '密码'-- 2. 使用链接服务器同步数据CREATE PROCEDURE usp_SyncPersonnelData_LinkedServerASBEGIN SET NOCOUNT ON BEGIN TRY BEGIN TRANSACTION -- 获取远程数据 SELECT CAST(工号 AS INT) AS PersonNo, 姓名 AS PersonName, 直间接 AS DutyType INTO #TempPersonnel FROM [RemoteHR].gwidb.dbo.out_TANXUEMEISYSTEMpawf -- 批量更新操作(同上) -- ... (更新和插入代码与方案一相同) DROP TABLE #TempPersonnel COMMIT TRANSACTION END TRY BEGIN CATCH ROLLBACK TRANSACTION THROW END CATCHEND
CREATE PROCEDURE usp_SyncPersonnelData_OpenQueryASBEGIN SET NOCOUNT ON -- 使用OPENQUERY执行复杂的远程查询 SELECT * INTO #TempPersonnel FROM OPENQUERY(RemoteHR, ' SELECT CAST(工号 AS INT) AS PersonNo, 姓名 AS PersonName, 直间接 AS DutyType FROM gwidb.dbo.out_TANXUEMEISYSTEMpawf WHERE 直间接 IN (''直'', ''间接'') -- 可以在远程过滤数据 ') -- 后续处理同上...END
-- 创建测试存储过程,对比三种方式性能CREATE PROCEDURE usp_TestSyncPerformanceASBEGIN DECLARE @StartTime DATETIME, @EndTime DATETIME -- 测试OPENDATASOURCE SET @StartTime = GETDATE() EXEC usp_SyncPersonnelData SET @EndTime = GETDATE() PRINT 'OPENDATASOURCE耗时:' + CAST(DATEDIFF(ms, @StartTime, @EndTime) AS VARCHAR) + 'ms' -- 测试链接服务器 SET @StartTime = GETDATE() EXEC usp_SyncPersonnelData_LinkedServer SET @EndTime = GETDATE() PRINT '链接服务器耗时:' + CAST(DATEDIFF(ms, @StartTime, @EndTime) AS VARCHAR) + 'ms' -- 测试OPENQUERY SET @StartTime = GETDATE() EXEC usp_SyncPersonnelData_OpenQuery SET @EndTime = GETDATE() PRINT 'OPENQUERY耗时:' + CAST(DATEDIFF(ms, @StartTime, @EndTime) AS VARCHAR) + 'ms'END
-- 创建同步日志表CREATE TABLE SyncLog ( LogID INT IDENTITY PRIMARY KEY, SyncTime DATETIME DEFAULT GETDATE(), SyncType NVARCHAR(50), RecordsAffected INT, Status NVARCHAR(20), ErrorMessage NVARCHAR(MAX))-- 最终版同步存储过程CREATE PROCEDURE usp_SyncHRData @SyncType NVARCHAR(20) = 'ALL', -- ALL, PERSONNEL, DEPT @DebugMode BIT = 0 -- 1:只显示不执行ASBEGIN SET NOCOUNT ON DECLARE @StartTime DATETIME = GETDATE() DECLARE @RecordsAffected INT = 0 DECLARE @Status NVARCHAR(20) = 'SUCCESS' DECLARE @ErrorMessage NVARCHAR(MAX) = '' BEGIN TRY -- 检查链接服务器是否可用 IF NOT EXISTS (SELECT 1 FROM sys.servers WHERE name = 'RemoteHR') BEGIN RAISERROR('链接服务器RemoteHR不存在,请先创建', 16, 1) RETURN END BEGIN TRANSACTION -- 1. 获取远程数据 SELECT CAST(工号 AS INT) AS PersonNo, 姓名 AS PersonName, 直间接 AS DutyType INTO #TempData FROM OPENQUERY(RemoteHR, ' SELECT 工号, 姓名, 直间接 FROM gwidb.dbo.out_TANXUEMEISYSTEMpawf WHERE 工号 IS NOT NULL ') IF @DebugMode = 1 BEGIN SELECT * FROM #TempData ROLLBACK TRANSACTION RETURN END -- 2. 根据类型同步数据 IF @SyncType IN ('ALL', 'PERSONNEL') BEGIN -- 更新离职人员 UPDATE dp SET Workflag = 'N', LastUpdate = GETDATE() FROM syteline.SHATDB.dbo.DeptPerson dp LEFT JOIN #TempData td ON dp.PersonNo = td.PersonNo WHERE td.PersonNo IS NULL AND dp.Workflag = 'Y' SET @RecordsAffected = @RecordsAffected + @@ROWCOUNT -- 更新/新增在职人员 UPDATE dp SET [Name] = td.PersonName, Duty = td.DutyType, Workflag = 'Y', LastUpdate = GETDATE() FROM syteline.SHATDB.dbo.DeptPerson dp INNER JOIN #TempData td ON dp.PersonNo = td.PersonNo SET @RecordsAffected = @RecordsAffected + @@ROWCOUNT INSERT INTO syteline.SHATDB.dbo.DeptPerson ( PersonNo, [Name], Workflag, Duty, CreateTime, LastUpdate ) SELECT td.PersonNo, td.PersonName, 'Y', td.DutyType, GETDATE(), GETDATE() FROM #TempData td WHERE NOT EXISTS ( SELECT 1 FROM syteline.SHATDB.dbo.DeptPerson dp WHERE dp.PersonNo = td.PersonNo ) SET @RecordsAffected = @RecordsAffected + @@ROWCOUNT END -- 3. 记录日志 INSERT INTO SyncLog (SyncTime, SyncType, RecordsAffected, Status, ErrorMessage) VALUES (GETDATE(), @SyncType, @RecordsAffected, @Status, @ErrorMessage) COMMIT TRANSACTION -- 4. 输出结果 PRINT '同步完成!' PRINT '类型:' + @SyncType PRINT '耗时:' + CAST(DATEDIFF(second, @StartTime, GETDATE()) AS VARCHAR) + '秒' PRINT '处理记录数:' + CAST(@RecordsAffected AS VARCHAR) END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION SET @Status = 'FAILED' SET @ErrorMessage = ERROR_MESSAGE() -- 记录错误日志 INSERT INTO SyncLog (SyncTime, SyncType, RecordsAffected, Status, ErrorMessage) VALUES (GETDATE(), @SyncType, 0, @Status, @ErrorMessage) PRINT '同步失败:' + @ErrorMessage END CATCH -- 清理临时表 IF OBJECT_ID('tempdb..#TempData') IS NOT NULL DROP TABLE #TempDataEND
-- 1. 创建链接服务器(首次使用)EXEC sp_addlinkedserver @server = 'RemoteHR', @provider = 'SQLOLEDB', @datasrc = '192.168.1.100' -- 远程服务器IPEXEC sp_addlinkedsrvlogin @rmtsrvname = 'RemoteHR', @rmtuser = 'sa', @rmtpassword = 'YourPassword'-- 2. 测试模式(不实际执行)EXEC usp_SyncHRData @DebugMode = 1-- 3. 正式同步所有数据EXEC usp_SyncHRData-- 4. 只同步人员数据EXEC usp_SyncHRData @SyncType = 'PERSONNEL'-- 5. 查看同步日志SELECT * FROM SyncLog ORDER BY SyncTime DESC
SET LOCK_TIMEOUT 30000 | |
OPENDATASOURCE:临时使用,配置简单
链接服务器:频繁使用,性能更好
OPENQUERY:复杂查询,可远程过滤
集合操作替代游标:性能提升10倍以上
阅读原文:原文链接