如何在SQL中避免游标复制表?
我想用SQL编写脚本,将这两个表(A,B)复制到与A,B结构相同的其他两个表(C,D) 重要:如何在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
________________________ _________________
| 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
。