set identity_insert <table> on
y dbcc checkident
son sus amigos aquí. Esto es algo así como lo que hice en el pasado (ver ejemplo de código). La única advertencia real es que el proceso de actualización es el único que puede insertar datos: todos los demás tienen que salir del grupo mientras se lleva a cabo la actualización. Podría, por supuesto, hacer este tipo de mapeo programáticamente antes de cargar las tablas de producción. Pero se aplica la misma restricción en las inserciones: el proceso de actualización es el único que se puede jugar.
--
-- start with a source schema -- doesn't actually need to be SQL tables
-- but from the standpoint of demonstration, it makes it easier
--
create table source.parent
(
id int not null primary key ,
data varchar(32) not null ,
)
create table source.child
(
id int not null primary key ,
data varchar(32) not null ,
parent_id int not null foreign key references source.parent(id) ,
)
--
-- On the receiving end, you need to create staging tables.
-- You'll notice that while there are primary keys defined,
-- there are no foreign key constraints. Depending on the
-- cleanliness of your data, you might even get rid of the
-- primary key definitions (though you'll need to add
-- some sort of processing to clean the data one way or
-- another, obviously).
--
-- and, depending context, these could even be temp tables
--
create table stage.parent
(
id int not null primary key ,
data varchar(32) not null ,
)
create table stage.child
(
id int not null primary key ,
data varchar(32) not null ,
parent_id int not null ,
)
--
-- and of course, the final destination tables already exist,
-- complete with identity properties, etc.
--
create table dbo.parent
(
id int not null identity(1,1) primary key ,
data varchar(32) not null ,
)
create table dbo.child
(
id int not null identity(1,1) primary key ,
data varchar(32) not null ,
parent_id int not null foreign key references dbo.parent(id) ,
)
-----------------------------------------------------------------------
-- so, you BCP or otherwise load your staging tables with the new data
-- frome the source tables. How this happens is left as an exercise for
-- the reader. We'll just assume that some sort of magic happens to
-- make it so. Don't forget to truncate the staging tables prior to
-- loading them with data.
-----------------------------------------------------------------------
-------------------------------------------------------------------------
-- Now we get to work to populate the production tables with the new data
--
-- First we need a map to let us create the new identity values.
-------------------------------------------------------------------------
drop table #parent_map
create table #parent_map
(
old_id int not null primary key nonclustered ,
offset int not null identity(1,1) unique clustered ,
new_id int null ,
)
create table #child_map
(
old_id int not null primary key nonclustered ,
offset int not null identity(1,1) unique clustered ,
new_id int null ,
)
insert #parent_map (old_id) select id from stage.parent
insert #child_map (old_id) select id from stage.child
-------------------------------------------------------------------------------
-- now that we've got the map, we can blast the data into the production tables
-------------------------------------------------------------------------------
--
-- compute the new ID values
--
update #parent_map set new_id = offset + (select max(id) from dbo.parent)
--
-- blast it into the parent table, turning on identity_insert
--
set identity_insert dbo.parent on
insert dbo.parent (id,data)
select id = map.new_id ,
data = staging.data
from stage.parent staging
join #parent_map map on map.old_id = staging.id
set identity_insert dbo.parent off
--
-- reseed the identity properties high water mark
--
dbcc checkident dbo.parent , reseed
--
-- compute the new ID values
--
update #child_map set new_id = offset + (select max(id) from dbo.child)
--
-- blast it into the child table, turning on identity_insert
--
set identity_insert dbo.child on
insert dbo.child (id , data , parent_id)
select id = parent.new_id ,
data = staging.data ,
parent_id = parent.new_id
from stage.child staging
join #child_map map on map.old_id = staging.id
join #parent_map parent on parent.old_id = staging.parent_id
set identity_insert dbo.child off
--
-- reseed the identity properties high water mark
--
dbcc checkident dbo.child , reseed
------------------------------------
-- That's about all there is too it.
------------------------------------
La cuestión clave es cómo son los registros secundarios relacionados con los registros primarios antes de que sean puestos en las mesas? – RBarryYoung
Puede quitar un bloqueo de tabla en todas las tablas afectadas antes de recuperar el siguiente valor de identidad, esto garantizaría que otros procesos/clientes no puedan alterar sus identificadores generados. De lo contrario, quizás necesite una forma diferente de generar identificadores, como un generador de hilos. –