小编典典

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

sql

我想用SQL编写脚本,该脚本会将这2个表(A,B)复制到其他2个表(C,D),并具有与A,B相同的结构。

重要提示

  1. 表C,d是 不是 必要的空
  2. 多个进程可以同时调用脚本

表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复制到CI时,需要知道,ID = 21现在映射到ID = 51,ID = 32映射到ID = 52。最后,表C将为:

   ________________________
   |        Table C       |
   |______________________|
   | id     FK_C_D   name |
   | ----- -------- ------|
   | 61      51       n1  |
   | 62      52       n2  |
   ------------------------

由于多个进程可能同时调用脚本,因此我无法更改表A,B来添加一些帮助程序列。因此,为了达到这个目的,我使用了CURSOR。我逐行复制表B和托管临时表以将OldId映射到NewId(21->
51,32-> 52),然后使用此临时表复制表A。

我读过CURSOR是不好的做法。那么,还有另一种方法吗?

谢谢


阅读 157

收藏
2021-04-07

共1个答案

小编典典

您可以将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
2021-04-07