【问题标题】:Cloning A Table Along With Its Foreign Keys克隆表及其外键
【发布时间】:2015-10-19 19:08:06
【问题描述】:

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

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

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

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

【问题讨论】:

  • 您到底遇到了什么问题?不确定您的 RDBM,但在 SQL Server 中,您可以简单地用关系编写对象、进行批量复制、数据导入向导、编写对象和数据等
  • @Kritner 我不是想复制表格本身,而是复制表格中的条目以获取测试数据。
  • 这是什么 RDBM?如果您使用的是 SQL Server,您可以尝试使用插入的 inserted
  • @Kritner 使用 SQL Server。我不确定你的意思。如果我要复制整个表 1,每个条目都必须有新的 guid,这不是问题。但是我如何建立关系以复制使用表 1 作为外键的表 2 中的所有条目。
  • select @var = Scope_Identity()

标签: sql-server tsql clone


【解决方案1】:

基本上,我们希望复制具有新 ID 的表,但保持与原始表的关系相同。 如果需要,您可以保留相同的 ID,但实际上这不应该是必需的;对于测试,ID 应该无关紧要 - 只有关系。

我将用两个表格来演示:

第一个是AnimalType with Id (uniqueidentifier - RowGuid, Primary Key) and AnimalType (nvarchar) Columns

第二个是 AnimalName (nvarchar) 和 AnimalType (uniqueidentifier, Foreign Key) Columns的Animal

对于父/查找表:

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

使用其默认的主键 ID 列(ROWGUID、IDENTITY 等)创建 newTable

在 newTable 中创建一个额外的 Column 来保存 oldTable 的 Id Column 值的副本

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

第二个(子)表:

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

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

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

创建后,我们使用原始表中的数据填充新的父/查找表,并将 Id 值放置在为该数据添加的额外列中。 Table 自己的 Id 会像往常一样生成唯一的。

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

接下来,我们在保存原始 Id 值的 Columns 上加入两个新表,并将外键列值更新为父/查找表中的新 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

【讨论】:

    【解决方案2】:
    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
    

    【讨论】:

      猜你喜欢
      • 2021-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-29
      • 2016-09-30
      • 1970-01-01
      相关资源
      最近更新 更多