克隆表及其外键

时间:2015-10-19 19:08:06

标签: sql-server tsql clone

如何克隆带有guid的表以及另一个将这些guid作为外键引用的表。

这两个表有一对多的关系。我需要以自动方式执行此操作。

我的问题是能够在克隆过程中创建新创建的guid时引用两个表之间的关系。

编辑:我需要将条目克隆到表本身,而不是新表。

2 个答案:

答案 0 :(得分:1)

基本上,我们希望使用新的ID复制表,但保持关系与原始相同。 如果需要,你可以保持相同的ID,但在实践中这不应该是一个要求;对于测试,ID应该不重要 - 只有关系。

我将用两个表来证明这一点:

第一个是具有Id的AnimalType(uniqueidentifier - RowGuid,主键)和AnimalType(nvarchar)列

第二个是Animal with AnimalName(nvarchar)和AnimalType(uniqueidentifier,Foreign Key)列

对于父/查找表:

创建一个新表(newTable)以填充现有表(oldTable)的数据。

创建具有自己的主键ID列(ROWGUID,IDENTITY等)的newTable及其默认值

在newTable中创建一个额外的列,以保存oldTable的Id列值的副本

newTable中的Id列将在创建记录时生成唯一的ID

第二个(子)表:

创建一个新表(newChildTable)以填充现有表(oldChildTable)的数据。

使用自己的外键列创建newChildTable以指向newTable的主键列

在newChildTable中创建一个额外的列,以保存oldChildTable的外键列值的副本

创建后,我们使用原始表中的数据填充新的父/查找表,将Id值放入为此数据添加的额外列中。 Table自己的ID将像往常一样独特生成。

接下来,我们使用原始Table中的数据填充子Table,将原始外键列值放入此数据的添加列中。

接下来,我们在列上保存原始Id值的两个新表,并将外键列值更新为父/查找表中的新ID。

最后,我们可以删除包含原始Id值的列,并且我们留下两个链接到相同数据的表,但是在复制记录时创建时创建的新ID。

您将无法参考原始ID - 只是在您的测试中随时选择了错误的表格(尽管这应该在不同的服务器中完成......)。如果您也需要原始ID,您可以执行上述操作,而不是移动ID,重命名列等 - 正如您所希望的那样。

/*
Create copy of parent/lookup Table with its own Id column
Add a column to hold the original Ids
*/
CREATE TABLE [dbo].[AnimalTypeBak](
    [Id] [uniqueidentifier] ROWGUIDCOL  NOT NULL CONSTRAINT [DF_AnimalTypeBak_Id]  DEFAULT (newid()),
    [OriginalId] [uniqueidentifier] NOT NULL,
    [AnimalType] [nvarchar](32) NOT NULL,
 CONSTRAINT [PK_AnimalTypeBak] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)
) ON [PRIMARY]
GO

/*
Create copy of child Table
Add a column to hold the original Foreign Key values
*/
CREATE TABLE [dbo].[AnimalBak](
    [AnimalName] [nvarchar](20) NOT NULL,
    [OriginalAnimalType] [uniqueidentifier] NOT NULL,
    [AnimalType] [uniqueidentifier] NOT NULL
) ON [PRIMARY]

GO

/*
Import data from the parent/lookup Table placing the origional Ids into the added Column
*/
INSERT INTO [dbo].[AnimalTypeBak]
           ([OriginalId]
           ,[AnimalType])
           SELECT [Id], [AnimalType]
           FROM [dbo].[AnimalType]
GO

/*
Import data from the child Table placing the origional Foreign Key values into the added Column
*/
INSERT INTO [dbo].[AnimalBak]
           ([OriginalAnimalType]
           ,[AnimalName])
           SELECT [AnimalType], [AnimalName]
           FROM [dbo].[Animal]
GO

/*
Update the child Table placing the new parent/lookup Ids into the Foreign Key Column
*/
UPDATE [dbo].[AnimalBak]
  SET [dbo].[AnimalBak].[AnimalType] = [dbo].[AnimalTypeBak].[Id]
  FROM [dbo].[AnimalBak]
  INNER JOIN [dbo].[AnimalTypeBak]
  ON [dbo].[AnimalBak].[OriginalAnimalType] = [dbo].[AnimalTypeBak].[OriginalId]
GO

/*
Drop the redundant Columns
*/
ALTER TABLE [dbo].[AnimalBak]
    DROP COLUMN [OriginalAnimalType]
GO

ALTER TABLE [dbo].[AnimalTypeBak]
    DROP COLUMN [OriginalId]

/*
Add the Foreign Key Contraint between the two Tables
*/
ALTER TABLE [dbo].[AnimalBak]  WITH CHECK ADD  CONSTRAINT [FK_AnimalBak_AnimalTypeBak] FOREIGN KEY([AnimalType])
REFERENCES [dbo].[AnimalTypeBak] ([Id])
GO

/*
And select the data to ensure the data is related as it was in the original Tables
*/
SELECT a.AnimalName, a.AnimalType, b.AnimalType FROM [dbo].[AnimalBak] as a INNER JOIN [dbo].[AnimalTypeBak] as b ON b.Id = a.AnimalType

答案 1 :(得分:0)

declare @Parents table (Id uniqueidentifier, Name varchar(50));
declare @Children table (Id uniqueidentifier, ParentId uniqueidentifier, Name varchar(50));

declare @NewId uniqueidentifier = newid();

insert into @Parents values (@NewId, 'Original parent');
insert into @Children values (newid(), @NewId, 'First original child');
insert into @Children values (newid(), @NewId, 'Second original child');


declare @Ids table (CloneId uniqueidentifier, OriginalId uniqueidentifier);


merge @Parents as target
    using (
        select 
            CloneId = newid(),
            OriginalId = Id,
            Name = Name + ' (Cloned)'
        from
            @Parents
        where   
            Id = @NewId
    ) 
    as source on source.CloneId = target.Id

when not matched by target then
    insert (Id, Name)   
    values (source.CloneId, source.Name)

output 
    source.CloneId, source.OriginalId
    into @Ids (CloneId, OriginalId);



merge @Children as target
    using (
        select 
            Id = newid(),
            ParentId = ids.CloneId,
            Name = Name + ' (Cloned)'
        from
            @Children c
            inner join @Ids ids on ids.OriginalId = c.ParentId
    ) 
    as source on source.Id = target.Id

when not matched by target then
    insert (Id, ParentId, Name) 
    values (source.Id, source.ParentId, source.Name);



select * from @Parents

select * from @Children