简体   繁体   English

避免 MERGE 问题的解决方法是什么,即 MERGE 语句的目标不能是远程表?

[英]What could be the workaround to avoid the MERGE issue i.e. The target of a MERGE statement cannot be a remote table?

Copying data from one table to another both on different servers but similar structures.将数据从一个表复制到另一个在不同服务器上但结构相似的表。

Ended up on this.到此为止。

declare @ClassIds table (OldClassId int, NewClassId int);


merge into newDB.dbo.tblClasses as target
    using
    (
        select
            Id = Id * (-1),
            [Name]  
        from
            oldDB.dbo.tblClasses
    )
    as source on source.Id = target.Id

when not matched by target then
    insert ([Name])
    values (source.[Name])

output source.Id * (-1), inserted.Id      -- ← the trick is here
into @ClassIds (OldClassId, NewClassId); 


insert into newDB.dbo.tblStudents
select
    s.Id,
    s.[Name],
    ClassId = ids.NewClassId
from
    oldDB.dbo.tblStudents s
    inner join @ClassIds ids on ids.OldClassId = s.ClassId;

but error:但错误:

The target of a MERGE statement cannot be a remote table, a remote view, or a view over remote tables. MERGE 语句的目标不能是远程表、远程视图或远程表上的视图。

Workaround could be reversing ie target and server but that's not ideal in my situation.解决方法可能是反转即目标和服务器,但这在我的情况下并不理想。

What should I do?我该怎么办?

Original question:原问题:

Original question 原始问题

Reason to do this:这样做的原因:

the reason is I am copying the parent-child data and in the target the references to parent would be lost since the primary keys are auto generated hence in target a new record in parent would generate new Id but child would have the old parent id as of the source hence lost.原因是我正在复制父子数据,并且在目标中对父级的引用将丢失,因为主键是自动生成的,因此在目标中父级中的新记录将生成新的 Id 但子级将具有旧的父级 ID来源因此丢失。 So to avoid that the merge would make sure tyo update the child record with new parent ids.因此,为了避免合并将确保使用新的父 ID 更新子记录。

edit:编辑:

the newDB is on the different server ie [192.168.xxx.xxx].newDB.dbo.tblStudents newDB 在不同的服务器上,即[192.168.xxx.xxx].newDB.dbo.tblStudents

If you are not able to change the remote DB structure, I would suggest to build the ClassId mapping table right in the target Class table:如果您无法更改远程数据库结构,我建议在目标类表中构建 ClassId 映射表:

drop table if exists #ClassIdMap;
create table #ClassIdMap (SourceClassId int, TargetClassId int);
declare @Prefix varchar(10) = 'MyClassId=';

insert into targetServer.targetDb.dbo.Classes
    ([Name])
select
    -- insert the source class id values with some unique prefix
    [Name] = concat(@Prefix, Id)
from 
    sourceServer.sourceDb.dbo.Classes;

-- then create the ClassId mapping table
-- getting the SourceClassId by from the target Name column 

insert #ClassIdMap (
    SourceClassId,
    TargetClassId)
select
    SourceClassId = replace([Name], @Prefix, ''),
    TargetClassId = Id
from
    targetServer.targetDb.dbo.Class
where
    [Name] like @Prefix + '%';

-- replace the source Ids with the Name values 

update target set
    [Name] = source.[Name]
from
    targetServer.targetDb.dbo.Class target
    inner join #ClassIdMap map on map.TargetClassId = target.Id
    inner join sourceServer.sourceDb.dbo.Classes source on source.Id = map.SourceClassId;

-- and use the ClassId mapping table 
-- to insert Students into correct classes

insert into targetServer.targetDb.dbo.Students (
    [Name]  ,
    ClassId )
select
    s.[Name],
    ClassId = map.TargetClassId
from
    sourceServer.sourceDb.dbo.Students s
    inner join #ClassIdMap map on map.SourceClassId = s.ClassId;

The problem or risk with this script is that it is not idempotent — being executed twice it creates the duplicates.此脚本的问题或风险在于它不是幂等的——执行两次会创建重复项。 To eliminate this risk, it is necessary to somehow remember on the source side what has already been inserted.为了消除这种风险,有必要以某种方式在源端记住已经插入的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM