简介这份资源面向金蝶K3 WISE的二次开发与运维人员提供基础资料同步所需的SQL语句集合用于解决ERP系统中职员、物料、客户、供应商、计量单位、仓库等主数据在数据库层面的同步与维护问题。压缩包内共15个sql文件整体约30KB按业务对象分别组织涵盖物料、客户、供应商、职员、部门、仓库、计量单位及其对应类别的同步存储过程另附辅助表同步脚本便于按模块直接调用或二次修改。内容以存储过程形式实现结构清晰适合需要批量同步基础资料、排查数据一致性问题的技术人员参考。目前已有1348人学习下载可作为K3 WISE数据集成与接口开发的实用脚本素材帮助读者快速理解各基础资料表的同步逻辑与字段映射关系减少重复编写SQL的工作量。1. K3 wise基础资料同步sql语句从账套隔离到增量落地的完整路径金蝶K3 WISE的基础资料同步是很多制造业和商贸企业ERP运维绕不开的活。物料、客户、供应商、BOM、计量单位、仓库这些主数据一旦在多个账套之间不一致采购下单找不到供应商、生产领料对不上物料编码、财务对账科目挂错问题就会像滚雪球一样越滚越大。手工在界面里一条条维护几百条还能忍上万条就是灾难。所以真正落地的做法是直接写SQL语句在数据库层面做同步。这篇文章讲的就是K3 WISE基础资料同步的SQL语句怎么写、怎么跑、参数怎么设、坑在哪。适合已经能连上SQL Server、看得懂K3表结构、想把这套同步做成可重复执行脚本的运维和二次开发人员。下面从表结构认知开始一路讲到增量同步和校验。2. K3 WISE基础资料的表结构先搞清楚数据存在哪几张表2.1 基础资料的三大类表主表、明细表、辅助表K3 WISE的数据库结构有个很明显的特征一类基础资料往往不是一张表能装下的。以物料为例t_ICItem是物料主表存的是物料编码、名称、规格、计量单位这些核心字段t_ICItemMaterial存的是物料的材质、重量等扩展属性t_ICItemPlan存的是计划相关参数t_ICItemQuality存的是质检信息。客户和供应商则集中在t_Organization这张表里通过FType字段区分是客户还是供应商。BOM稍微特殊t_ICBOM是BOM头t_ICBOMChild是BOM子项两张表通过FInterID关联。理解这个结构的意义在于同步基础资料不是同步一张表而是同步一组有主从关系的表。如果你只同步了t_ICItem物料在目标账套里能查到但一跑MRP就报错因为计划参数表里没有对应记录。这是最常见的翻车点之一。下面这张表列出几类常见基础资料对应的核心表方便你对照基础资料类型主表关键关联表关联字段物料t_ICItemt_ICItemPlan、t_ICItemMaterialFItemID客户/供应商t_Organizationt_OrganizationContactFItemIDBOMt_ICBOMt_ICBOMChildFInterID计量单位t_MeasureUnitt_MeasureUnitGroupFMeasureUnitID仓库t_Stock—FStockID部门t_Department—FItemID这张表不是让你背而是让你在写同步语句之前先确认目标基础资料涉及哪几张表缺一张都会导致同步后功能异常。2.2 账套隔离机制为什么不能直接跨库INSERTK3 WISE每个账套对应一个独立的数据库账套之间通过数据库名区分。很多人第一反应是写INSERT INTO 目标库.dbo.t_ICItem SELECT * FROM 源库.dbo.t_ICItem跨库查询在同一个SQL Server实例下确实能跑但直接这么干会出问题。核心原因是K3 WISE的主键生成机制。t_ICItem的FItemID不是自增列而是由K3的BOS平台通过内部计数器分配的。如果你直接把源账套的FItemID插到目标账套短期内看起来没问题但目标账套后续新建物料时BOS平台分配的ID可能和已插入的ID冲突导致主键重复或者数据错乱。这个坑非常隐蔽可能同步完一个月后才爆发。正确的做法是同步时只同步业务字段FItemID在目标账套重新生成。但重新生成又带来新问题——BOM子项里引用的FItemID是源账套的直接搬过去就指向了错误的物料。所以BOM同步必须做ID映射这是后面章节要展开的内容。2.3 用SQL语句查询基础资料先看清数据再动手在写同步语句之前先用查询语句把源账套和目标账套的数据摸清楚。这一步很多人跳过结果同步时才发现字段对不上、编码规则不一致。查物料主表的基本信息-- 查询源账套物料主表确认字段和数量 SELECT FItemID, -- 物料内码K3内部唯一标识 FNumber, -- 物料编码业务唯一 FName, -- 物料名称 FModel, -- 规格型号 FUnitID, -- 计量单位内码 FDeleted -- 删除标记0为正常1为已删除 FROM t_ICItem WHERE FDeleted 0 -- 只查未删除的 ORDER BY FNumber;这段语句的作用是确认源账套里有多少条有效物料、编码规则是什么样的。FDeleted字段必须加上K3 WISE的删除是逻辑删除不加这个条件会把已删除的物料也同步过去。FItemID和FNumber的关系要特别注意FItemID是系统内部用的FNumber是业务人员看到的同步时以FNumber作为匹配依据FItemID只作为关联查询的桥梁。查客户和供应商-- 查询客户和供应商FType区分类型 SELECT FItemID, FNumber, FName, FType, -- 1客户2供应商具体值以账套实际配置为准 FDeleted FROM t_Organization WHERE FDeleted 0 ORDER BY FType, FNumber;FType的取值在不同版本和配置下可能有差异不要凭记忆写死先跑一条SELECT DISTINCT FType FROM t_Organization确认。这是血泪经验我见过有人把客户当供应商同步过去采购订单里选出来的全是客户。3. 基础资料同步SQL语句的编写从单表到多表的落地脚本3.1 单表同步物料主表的最小可用语句先从一个最简单的场景开始把源账套的物料主表同步到目标账套目标账套已存在的物料做更新不存在的做插入。这种「存在即更新不存在即插入」的模式在SQL Server里通常用MERGE语句实现但K3 WISE的运维场景下我更推荐用UPDATE加INSERT分开写因为MERGE在并发场景下有已知的锁问题而且出错时不好排查。先写更新语句-- 更新目标账套中已存在的物料 UPDATE target_db.dbo.t_ICItem SET FName src.FName, FModel src.FModel, FUnitID src.FUnitID, FDeleted src.FDeleted FROM target_db.dbo.t_ICItem AS target INNER JOIN source_db.dbo.t_ICItem AS src ON target.FNumber src.FNumber -- 以物料编码为匹配键 WHERE src.FDeleted 0;这段语句的逻辑是通过FNumber把源账套和目标账套的物料关联起来用源账套的字段值更新目标账套。FNumber是业务唯一键用它做匹配比FItemID可靠因为两个账套的FItemID大概率不一致。注意FUnitID这里直接搬了源账套的值如果两个账套的计量单位表不一致这个字段会指向错误的单位后面3.3节会讲怎么处理。再写插入语句-- 插入目标账套中不存在的物料 INSERT INTO target_db.dbo.t_ICItem ( FNumber, FName, FModel, FUnitID, FDeleted ) SELECT src.FNumber, src.FName, src.FModel, src.FUnitID, 0 FROM source_db.dbo.t_ICItem AS src WHERE src.FDeleted 0 AND NOT EXISTS ( SELECT 1 FROM target_db.dbo.t_ICItem AS target WHERE target.FNumber src.FNumber );插入语句的关键在NOT EXISTS子查询它确保只插入目标账套里没有的物料。这里没有插入FItemID因为FItemID需要由目标账套的BOS平台分配。但问题来了不插入FItemIDK3界面里能正常显示吗答案是短期可以长期会出问题。K3 WISE的很多功能依赖FItemID做关联如果FItemID为空或者重复后续操作会报错。所以更稳妥的做法是插入时先获取目标账套当前的最大FItemID然后按顺序递增分配。但这样做有并发风险如果同步时有其他人在目标账套新建物料ID会冲突。常见的折中方案是同步脚本在业务低峰期执行执行前锁定相关表执行后释放。这个锁的操作后面3.4节展开。3.2 多表同步物料计划参数表的关联插入物料主表同步完之后t_ICItemPlan这张扩展表也必须同步否则MRP运算会报「物料计划参数缺失」。这张表的关联键是FItemID但两个账套的FItemID不一致所以不能直接搬。正确的做法是通过FNumber找到目标账套的FItemID再插入计划参数表。-- 同步物料计划参数表通过FNumber做ID映射 INSERT INTO target_db.dbo.t_ICItemPlan ( FItemID, -- 目标账套的物料内码 FPlanMode, -- 计划模式 FOrderPolicy, -- 订货策略 FLeadTime, -- 提前期 FBatchAppendQty -- 批量增量 ) SELECT target_item.FItemID, -- 从目标账套取FItemID src_plan.FPlanMode, src_plan.FOrderPolicy, src_plan.FLeadTime, src_plan.FBatchAppendQty FROM source_db.dbo.t_ICItemPlan AS src_plan INNER JOIN source_db.dbo.t_ICItem AS src_item ON src_plan.FItemID src_item.FItemID INNER JOIN target_db.dbo.t_ICItem AS target_item ON src_item.FNumber target_item.FNumber -- 通过编码映射 WHERE NOT EXISTS ( SELECT 1 FROM target_db.dbo.t_ICItemPlan AS target_plan WHERE target_plan.FItemID target_item.FItemID );这段语句的核心是两次JOIN第一次通过源账套的FItemID把计划参数和物料主表关联起来拿到物料编码第二次通过物料编码找到目标账套的FItemID再插入计划参数。这样FItemID就是目标账套自己的不会冲突。参数说明FPlanMode和FOrderPolicy是枚举值不同账套的配置可能不同同步前要确认两边的枚举定义一致。FLeadTime是提前期单位是天这个字段如果源账套是小时而目标账套是天同步过去就会出错。这类字段的映射关系需要在脚本里做转换不能直接搬。3.3 计量单位同步先同步单位再同步物料计量单位是基础资料里最容易被忽视的一环。很多人先同步物料同步完发现物料的FUnitID指向的单位在目标账套里不存在或者存在但换算率不对。正确的顺序是先同步计量单位组和计量单位再同步物料。-- 第一步同步计量单位组 INSERT INTO target_db.dbo.t_MeasureUnitGroup (FMeasureUnitGroupID, FNumber, FName) SELECT src.FMeasureUnitGroupID, src.FNumber, src.FName FROM source_db.dbo.t_MeasureUnitGroup AS src WHERE NOT EXISTS ( SELECT 1 FROM target_db.dbo.t_MeasureUnitGroup AS target WHERE target.FNumber src.FNumber ); -- 第二步同步计量单位通过组编码映射组ID INSERT INTO target_db.dbo.t_MeasureUnit (FMeasureUnitID, FNumber, FName, FMeasureUnitGroupID, FConversionRate) SELECT src_unit.FMeasureUnitID, src_unit.FNumber, src_unit.FName, target_group.FMeasureUnitGroupID, -- 用目标账套的组ID src_unit.FConversionRate FROM source_db.dbo.t_MeasureUnit AS src_unit INNER JOIN source_db.dbo.t_MeasureUnitGroup AS src_group ON src_unit.FMeasureUnitGroupID src_group.FMeasureUnitGroupID INNER JOIN target_db.dbo.t_MeasureUnitGroup AS target_group ON src_group.FNumber target_group.FNumber WHERE NOT EXISTS ( SELECT 1 FROM target_db.dbo.t_MeasureUnit AS target_unit WHERE target_unit.FNumber src_unit.FNumber );这里有个细节FMeasureUnitID直接搬了源账套的值。如果目标账套的计量单位表是空的或者ID段没有冲突这样做可以。但如果目标账套已经有计量单位ID可能冲突。稳妥的做法和物料一样通过FNumber匹配ID重新分配。但计量单位的ID被物料表引用重新分配后物料的FUnitID也要跟着改这就形成了一个依赖链。实际运维中如果目标账套的计量单位不多我一般建议手工维护不要用脚本同步因为换算率和精度问题很容易出错。3.4 同步脚本的事务与锁避免同步到一半翻车基础资料同步往往涉及多张表如果同步到一半失败目标账套的数据就处于不一致状态。比如物料主表插入了但计划参数表没插入MRP跑起来就报错。所以同步脚本必须放在事务里。BEGIN TRANSACTION; BEGIN TRY -- 同步计量单位组 -- 同步计量单位 -- 同步物料主表 -- 同步物料计划参数表 -- 同步客户/供应商 COMMIT TRANSACTION; PRINT 同步完成; END TRY BEGIN CATCH ROLLBACK TRANSACTION; PRINT 同步失败已回滚 ERROR_MESSAGE(); END CATCH;事务保证了要么全成功要么全回滚。但事务期间会持有锁如果同步的数据量大锁会阻塞其他用户的正常操作。所以同步脚本要在业务低峰期执行比如晚上十点以后。如果数据量特别大可以考虑分批同步每批一千条每批一个事务这样锁的粒度小一些。注意K3 WISE的数据库如果开启了Always On或者镜像大事务会导致日志暴涨同步前确认日志空间充足。4. 增量同步与去重让脚本可以反复跑而不出错4.1 用时间戳做增量只同步变更过的数据全量同步每次都要比对所有数据数据量大了之后效率很低。K3 WISE的基础资料表里很多都有FModifyDate或者类似的修改时间字段可以用它做增量。-- 增量同步物料只同步最近一天修改过的 DECLARE LastSyncTime DATETIME; SET LastSyncTime DATEADD(DAY, -1, GETDATE()); -- 同步最近一天的数据 SELECT FNumber, FName, FModel, FUnitID FROM source_db.dbo.t_ICItem WHERE FDeleted 0 AND FModifyDate LastSyncTime;LastSyncTime这个变量可以改成从配置表里读比如建一张t_SyncLog表记录上次同步的时间点每次同步完更新这个时间。这样脚本可以做成定时任务每天跑一次只同步变更过的数据。但要注意K3 WISE的FModifyDate不一定在所有表里都有有些表只有FCreateDate。如果只有创建时间增量同步就只能同步新增的修改过的同步不到。这种情况下要么用全量比对要么在源账套加触发器记录变更。触发器方案对源账套有性能影响要谨慎评估。4.2 去重查询目标账套已有数据不重复插入增量同步时同一批数据可能被同步多次比如脚本失败重跑。所以插入语句必须带NOT EXISTS或者NOT IN做去重。-- 去重插入目标账套已存在的物料编码不重复插入 INSERT INTO target_db.dbo.t_ICItem (FNumber, FName, FModel, FUnitID, FDeleted) SELECT src.FNumber, src.FName, src.FModel, src.FUnitID, 0 FROM source_db.dbo.t_ICItem AS src WHERE src.FDeleted 0 AND src.FModifyDate LastSyncTime AND NOT EXISTS ( SELECT 1 FROM target_db.dbo.t_ICItem AS target WHERE target.FNumber src.FNumber );NOT EXISTS比NOT IN更安全因为NOT IN在子查询返回NULL时会出问题。K3 WISE的FNumber字段一般不为空但保险起见还是用NOT EXISTS。如果目标账套里已经有了重复的物料编码比如之前手工维护时重复了NOT EXISTS只能保证不再插入新的重复已有的重复需要单独清理。清理语句-- 查询目标账套中重复的物料编码 SELECT FNumber, COUNT(*) AS 重复次数 FROM target_db.dbo.t_ICItem WHERE FDeleted 0 GROUP BY FNumber HAVING COUNT(*) 1;查到重复的编码后根据FItemID保留一条删除其余的。删除前要确认这些重复的物料有没有被BOM或者单据引用如果被引用了删除会导致数据断裂。这种清理操作风险很高建议先备份。4.3 用临时表做差异比对找出源和目标的不一致增量同步只能同步变更过的数据但如果目标账套的数据被误删或者误改增量同步发现不了。所以定期做一次全量差异比对是必要的。-- 用临时表找出源账套有但目标账套没有的物料 CREATE TABLE #MissingItems ( FNumber NVARCHAR(80), FName NVARCHAR(255) ); INSERT INTO #MissingItems (FNumber, FName) SELECT src.FNumber, src.FName FROM source_db.dbo.t_ICItem AS src WHERE src.FDeleted 0 AND NOT EXISTS ( SELECT 1 FROM target_db.dbo.t_ICItem AS target WHERE target.FNumber src.FNumber ); -- 查看差异 SELECT * FROM #MissingItems; -- 清理临时表 DROP TABLE #MissingItems;这个差异比对可以扩展成双向的源有目标没有、目标有源没有、两边都有但字段值不一致。字段值不一致的比对比较耗资源一般只比对关键字段比如名称、规格、计量单位。4.4 同步日志表记录每次同步的结果同步脚本跑完之后要留下记录方便排查问题。-- 创建同步日志表 CREATE TABLE t_SyncLog ( FLogID INT IDENTITY(1,1) PRIMARY KEY, FSyncTime DATETIME DEFAULT GETDATE(), FSyncType NVARCHAR(50), -- 同步类型物料、客户、BOM FInsertCount INT, -- 插入条数 FUpdateCount INT, -- 更新条数 FStatus NVARCHAR(20), -- 状态成功、失败 FMessage NVARCHAR(500) -- 备注信息 ); -- 同步完成后写入日志 INSERT INTO t_SyncLog (FSyncType, FInsertCount, FUpdateCount, FStatus, FMessage) VALUES (物料同步, ROWCOUNT, 0, 成功, 增量同步完成);ROWCOUNT返回上一条语句影响的行数可以用来记录插入或更新的条数。日志表积累一段时间后可以分析同步的频率和数据变化趋势对运维有帮助。5. 避坑与排查K3 WISE基础资料同步的五个血泪教训5.1 坑一同步后物料在界面看不到现象SQL语句执行成功t_ICItem表里也有数据但K3 WISE的物料界面里查不到。原因K3 WISE的界面查询不只是查t_ICItem还会关联t_ICItemPlan、t_ICItemMaterial等扩展表如果扩展表里没有对应记录界面会过滤掉这些物料。另外FDeleted字段如果为NULL而不是0界面也会认为已删除。解决同步物料时确保t_ICItemPlan等扩展表也同步了。FDeleted字段显式设置为0不要留NULL。检查语句-- 检查物料是否有对应的计划参数 SELECT i.FNumber, i.FName FROM t_ICItem AS i LEFT JOIN t_ICItemPlan AS p ON i.FItemID p.FItemID WHERE i.FDeleted 0 AND p.FItemID IS NULL;5.2 坑二BOM同步后子项指向错误的物料现象BOM同步过去了但打开BOM发现子项物料和源账套不一致或者子项显示为空。原因BOM子项表t_ICBOMChild里存的是FItemID直接搬源账套的FItemID在目标账套里指向了错误的物料或者不存在的物料。解决BOM同步必须做ID映射。先同步物料确保目标账套的物料编码和源账套一致然后通过编码映射FItemID。-- BOM子项同步通过物料编码映射FItemID INSERT INTO target_db.dbo.t_ICBOMChild (FInterID, FItemID, FQty, FPosition) SELECT target_bom.FInterID, target_item.FItemID, -- 目标账套的物料内码 src_child.FQty, src_child.FPosition FROM source_db.dbo.t_ICBOMChild AS src_child INNER JOIN source_db.dbo.t_ICBOM AS src_bom ON src_child.FInterID src_bom.FInterID INNER JOIN source_db.dbo.t_ICItem AS src_item ON src_child.FItemID src_item.FItemID INNER JOIN target_db.dbo.t_ICBOM AS target_bom ON src_bom.FNumber target_bom.FNumber INNER JOIN target_db.dbo.t_ICItem AS target_item ON src_item.FNumber target_item.FNumber;这段语句的关键是两次映射先通过BOM编号映射BOM头再通过物料编码映射物料内码。5.3 坑三计量单位换算率不一致导致数量错误现象物料同步过去了但采购订单里下单100个系统算出来是1000个。原因源账套和目标账套的计量单位换算率不一致。比如源账套里「箱」和「个」的换算率是1:100目标账套里是1:10同步后数量就差了十倍。解决同步计量单位时FConversionRate字段要确认两边一致。如果不一致要么在同步脚本里做转换要么先统一两边的计量单位配置。检查语句-- 比对两边计量单位的换算率 SELECT src.FNumber, src.FConversionRate AS 源换算率, target.FConversionRate AS 目标换算率 FROM source_db.dbo.t_MeasureUnit AS src INNER JOIN target_db.dbo.t_MeasureUnit AS target ON src.FNumber target.FNumber WHERE src.FConversionRate target.FConversionRate;5.4 坑四同步脚本锁表导致业务卡死现象同步脚本执行期间K3 WISE的界面操作非常慢甚至超时。原因同步脚本用了大事务持有表锁其他用户的查询和写入被阻塞。解决分批同步每批一千条左右每批一个事务。或者在同步前设置锁超时避免长时间等待。-- 设置锁超时为5秒 SET LOCK_TIMEOUT 5000; -- 分批同步示例 DECLARE BatchSize INT 1000; DECLARE Offset INT 0; WHILE 1 1 BEGIN BEGIN TRANSACTION; INSERT INTO target_db.dbo.t_ICItem (FNumber, FName, FModel, FUnitID, FDeleted) SELECT TOP (BatchSize) src.FNumber, src.FName, src.FModel, src.FUnitID, 0 FROM source_db.dbo.t_ICItem AS src WHERE src.FDeleted 0 AND NOT EXISTS ( SELECT 1 FROM target_db.dbo.t_ICItem AS target WHERE target.FNumber src.FNumber ) ORDER BY src.FNumber; IF ROWCOUNT 0 BEGIN COMMIT TRANSACTION; BREAK; END COMMIT TRANSACTION; ENDSET LOCK_TIMEOUT设置锁等待时间超过5秒就报错而不是一直等。分批同步用TOP (BatchSize)加循环每批提交一次事务锁的持有时间短。5.5 坑五同步后单据引用报「基础资料不存在」现象物料和客户都同步了但做采购订单时选客户提示「基础资料不存在」。原因K3 WISE的单据引用基础资料时不只是查t_Organization还会查t_OrganizationContact联系人表和t_OrganizationBank银行信息表。如果这些辅助表没有同步单据界面就选不到。解决同步客户和供应商时把联系人表和银行信息表也同步了。这两张表的关联键也是FItemID同样需要做ID映射。-- 同步客户联系人 INSERT INTO target_db.dbo.t_OrganizationContact (FItemID, FContact, FPhone, FEmail) SELECT target_org.FItemID, src_contact.FContact, src_contact.FPhone, src_contact.FEmail FROM source_db.dbo.t_OrganizationContact AS src_contact INNER JOIN source_db.dbo.t_Organization AS src_org ON src_contact.FItemID src_org.FItemID INNER JOIN target_db.dbo.t_Organization AS target_org ON src_org.FNumber target_org.FNumber WHERE NOT EXISTS ( SELECT 1 FROM target_db.dbo.t_OrganizationContact AS target_contact WHERE target_contact.FItemID target_org.FItemID );6. 进阶技巧用存储过程封装同步逻辑并做数据校验6.1 把同步脚本封装成存储过程同步脚本写多了之后散落在各个SQL文件里不好管理。更好的做法是封装成存储过程通过参数控制同步类型和同步模式。CREATE PROCEDURE usp_SyncBaseData SyncType NVARCHAR(50), -- 同步类型Item、Customer、BOM SyncMode NVARCHAR(20), -- 同步模式Full、Incremental LastSyncTime DATETIME NULL -- 增量同步的起始时间 AS BEGIN SET NOCOUNT ON; IF SyncType Item BEGIN -- 物料同步逻辑 IF SyncMode Full BEGIN -- 全量同步 EXEC usp_SyncItemFull; END ELSE BEGIN -- 增量同步 EXEC usp_SyncItemIncremental LastSyncTime; END END ELSE IF SyncType Customer BEGIN -- 客户同步逻辑 EXEC usp_SyncCustomer SyncMode, LastSyncTime; END -- 记录日志 INSERT INTO t_SyncLog (FSyncType, FStatus, FMessage) VALUES (SyncType, 成功, SyncMode 同步完成); END存储过程的好处是参数化调用不用每次改脚本可以嵌套调用把不同基础资料的同步逻辑拆成子过程方便做权限控制只给运维人员执行权限。6.2 同步后的数据校验用SQL语句做一致性检查同步完成之后不能只看日志说成功就完事要做数据校验。校验分三个层次数量校验、关键字段校验、关联完整性校验。数量校验-- 比对源账套和目标账套的物料数量 SELECT (SELECT COUNT(*) FROM source_db.dbo.t_ICItem WHERE FDeleted 0) AS 源物料数, (SELECT COUNT(*) FROM target_db.dbo.t_ICItem WHERE FDeleted 0) AS 目标物料数;关键字段校验-- 比对两边物料的名称和规格是否一致 SELECT src.FNumber, src.FName AS 源名称, target.FName AS 目标名称, src.FModel AS 源规格, target.FModel AS 目标规格 FROM source_db.dbo.t_ICItem AS src INNER JOIN target_db.dbo.t_ICItem AS target ON src.FNumber target.FNumber WHERE src.FName target.FName OR src.FModel target.FModel;关联完整性校验-- 检查目标账套中是否有物料缺少计划参数 SELECT i.FNumber, i.FName FROM target_db.dbo.t_ICItem AS i LEFT JOIN target_db.dbo.t_ICItemPlan AS p ON i.FItemID p.FItemID WHERE i.FDeleted 0 AND p.FItemID IS NULL;这三类校验跑完基本能确认同步的数据是可用的。校验语句也可以封装成存储过程每次同步后自动执行发现问题就发邮件告警。6.3 一个我常用的技巧用CHECKSUM做快速比对数据量大的时候逐字段比对很慢。我一般用CHECKSUM或者HASHBYTES做快速比对先找出哪些行可能不一致再对这些行做详细比对。-- 用CHECKSUM快速找出可能不一致的物料 SELECT src.FNumber, CHECKSUM(src.FName, src.FModel, src.FUnitID) AS 源校验和, CHECKSUM(target.FName, target.FModel, target.FUnitID) AS 目标校验和 FROM source_db.dbo.t_ICItem AS src INNER JOIN target_db.dbo.t_ICItem AS target ON src.FNumber target.FNumber WHERE CHECKSUM(src.FName, src.FModel, src.FUnitID) CHECKSUM(target.FName, target.FModel, target.FUnitID);CHECKSUM会有哈希冲突但概率很低用来做初步筛选足够了。找到不一致的行之后再逐字段看是哪个字段的问题。这个技巧在数据量几万条的时候特别有用比逐字段比对快很多。同步这件事我的习惯是每次改完脚本先在测试账套跑一遍用校验语句确认数据一致再上生产。生产环境执行前先备份目标账套的相关表万一出问题可以快速回滚。同步脚本不要追求一次写完就完美而是做成可以反复跑、每次跑完都能校验的闭环。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?