Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在SQL中避免游标复制表?_Sql_Sql Server_Tsql_Sql Server 2008_Stored Procedures - Fatal编程技术网

如何在SQL中避免游标复制表?

如何在SQL中避免游标复制表?,sql,sql-server,tsql,sql-server-2008,stored-procedures,Sql,Sql Server,Tsql,Sql Server 2008,Stored Procedures,我想用SQL编写脚本,将这两个表(A,B)复制到与A,B结构相同的其他两个表(C,D) 重要: 表C、D不必为空 多个进程可以同时调用脚本 表A具有表b的外键(fk_A_b) ________________________ _________________ | Table A | | Table B | |______________________| |_______________| | id FK_A_B

我想用SQL编写脚本,将这两个表(A,B)复制到与A,B结构相同的其他两个表(C,D)

重要

  • 表C、D不必为空
  • 多个进程可以同时调用脚本
  • 表A具有表b的外键(fk_A_b)

       ________________________  _________________
       |        Table A       |  |   Table B     |  
       |______________________|  |_______________|
       | id     FK_A_B   name |  | id    visible |
       | ----- -------- ------|  | ----- --------|
       | 1      21       n1   |  | 21     true   |
       | 5      32       n2   |  | 32     false  |
       ------------------------  -----------------
    
    假设在将表B复制到D之后,这就是我得到的结果

       ________________
       |   Table D    |  
       |______________|
       | id   visible |
       | ----- -------|
       | 51    true   |
       | 52    false  |
       ----------------
    
    现在,当我将表A复制到C时,我需要知道,不知何故,ID=21现在映射到ID=51,ID=32映射到ID=52。最后,表C将是:

       ________________________
       |        Table C       |
       |______________________|
       | id     FK_C_D   name |
       | ----- -------- ------|
       | 61      51       n1  |
       | 62      52       n2  |
       ------------------------
    
    因为多个进程可能同时调用脚本,所以我无法更改表A、B以添加一些帮助器列。所以,为了实现这一点,我使用了游标。我一行一行地复制表B和managed temp table,将OldId映射到NewId(21->51,32->52),然后使用这个temp table复制表A

    我已经读到光标是一种坏习惯。那么,还有别的办法吗


    谢谢

    您可以将output子句与merge语句一起使用,以获得源id和目标id之间的映射。 在这个问题中进行了描述

    下面是一些可以测试的代码。我使用表变量而不是实表

    设置示例数据:

    -- @A and @B is the source tables
    declare @A as table
    (
      id int,
      FK_A_B int,
      name varchar(10)
    )
    
    declare @B as table
    (
      id int,
      visible bit
    )  
    
    -- Sample data in @A and @B
    insert into @B values (21, 1),(32, 0)
    insert into @A values (1, 21, 'n1'),(5, 32, 'n2')
    
    
    -- @C and @D is the target tables with id as identity columns
    declare @C as table
    (
      id int identity,
      FK_C_D int not null,
      name varchar(10)
    )
    
    declare @D as table
    (
      id int identity,
      visible bit
    )  
    
    -- Sample data already in @C and @D
    insert into @D values (1),(0)
    insert into @C values (1, 'x1'),(1, 'x2'),(2, 'x3')
    
    复制数据:

    -- The @IdMap is a table that holds the mapping between
    -- the @B.id and @D.id (@D.id is an identity column)
    declare @IdMap table(TargetID int, SourceID int)
    
    -- Merge from @B to @D.
    merge @D as D             -- Target table
    using @B as B             -- Source table
    on 0=1                    -- 0=1 means that there are no matches for merge
    when not matched then
      insert (visible) values(visible)    -- Insert to @D
    output inserted.id, B.id into @IdMap; -- Capture the newly created inserted.id and
                                          -- map that to the source (@B.id)
    
    -- Add rows to @C from @A with a join to
    -- @IdMap to get the new id for the FK relation
    insert into @C(FK_C_D, name)
    select I.TargetID, A.name 
    from @A as A
      inner join @IdMap as I
        on A.FK_A_B = I.SourceID
    
    结果:

    select *
    from @D as D
      inner join @C as C
        on D.id = C.FK_C_D
    
    id          visible id          FK_C_D      name
    ----------- ------- ----------- ----------- ----------
    1           1       1           1           x1
    1           1       2           1           x2
    2           0       3           2           x3
    3           1       4           3           n1
    4           0       5           4           n2
    

    您可以在此处测试代码:

    例如,SQL Server将rowguid字段添加到某些发布中包含的用于合并复制的表中。我认为,这种方法可以用于您的任务。我们的想法是添加两个GUID字段,它们将扮演全局标识符的角色,因此我们可以在两对主数据ILS表中使用它们

    if object_id('tempdb..#TableB') is not null
        drop table #TableB
    
    select identity(int) RowId, *
    into #TableB
    from TableB
    
    if object_id('tempdb..#TableDIds') is not null
        drop table #TableDIds
    create table  #TableDIds (RowId int identity(1,1), Id int)
    
    insert TableD
    output inserted.Id into #TableDIds
    select Visible
    from #TableB
    order by RowId
    
    insert TableC
    select tdi.Id, ta.name
    from TableA ta
        join #TableB tb on
            ta.FK_A_B = tb.Id
        join #TableDIds tdi on
            tdi.RowId = tb.RowId
    
    我使用了以下设置:

    create table TableB
    (
        Id int not null primary key,
        Visible bit not null
    )
    
    create table TableA
    (
        Id int not null, 
        FK_A_B int not null foreign key references TableB(Id), 
        Name varchar(10) not null
    )
    
    create table TableD
    (
        Id int identity(1,1) primary key,
        Visible bit not null
    )
    
    create table TableC
    (
        Id int identity(1,1), 
        FK_C_D int not null references TableD(Id), 
        Name varchar(10) not null
    )
    
    insert TableB
    values
        (21, 1),
        (32, 0)
    
    insert TableA
    values
        (1, 21, 'n1'),
        (5, 32, 'n2')
    
    我希望这有帮助


    如果需要,可以从源表中保留相同的标识值。你有什么理由要创建新ID吗?@d-live,我写的表不是空的。源表中的标识值已经可以在目标表中使用。我将更深入地了解它,但乍一看似乎更复杂。它是否比游标更有效?@theateist-很难概括性能,但在这种情况下,我认为可以肯定地说,使用merge比使用游标的性能要好得多。@theateist-在链接问题中可能不明显,但使用merge时不需要使用循环。在您的例子中,您将有一个用于B->D的merge语句,其中包含映射id的输出。还有一个insert语句A-C,它连接来自合并的输出表以查找新id。它看起来确实很复杂,但值得了解。这是非常有用的。我要冒险说,这将比一辆汽车更有效率cursor@Alex-合并中B和D之间的映射是0=1上的
    ,这意味着合并中没有匹配项,因此
    B
    中的所有行都将插入到
    D