How to better duplicate a set of data in SQL Server

前端 未结 3 623
小蘑菇
小蘑菇 2020-12-21 00:29

I have several related tables that I want to be able to duplicate some of the rows while updating the references.

I want to duplicate a row in Table1, and all of

3条回答
  •  春和景丽
    2020-12-21 00:52

    I had the same need as the OP: cloning sql server tables where they are hierarchical sql server tables that contain foreign keys to one another. Or in other words, cloning sql server tables that have parent-child relationships.

    Starting with @Tony_O 's answer/SQL, I converted it to my needs but discovered that the last line '..from Fruit f join..' should be '..from Property f join..'. Also, @newBasket should be @iBasketId.

    So along with some other minor housekeeping fixes I found were needed for it to execute, plus using @Vladimir_Baranov 's DDL (with some missing parenthesis added), as well as making both of their SQL's object names consistent, since I had done the work I thought I would post it as a refinement of their work that will allow someone to to quickly test whether this solution solves their need. Just do 'find/replace' of the table names here with values from yours.

    And note that if your Properties table has more fields than the single 'PropertyText' one in this example, just make sure to join on those additional fields as noted in the comment in the script.

    -----------------
    --create tables--
    -----------------
    
    --Baskets
    CREATE TABLE [dbo].[Baskets](
        [BasketId] [int] IDENTITY(1,1) NOT NULL,
        [BasketName] [varchar](50) NOT NULL,
     CONSTRAINT [PK_Baskets] PRIMARY KEY CLUSTERED 
        (
            [BasketId] ASC
        )
    )
    
    --Fruits
    CREATE TABLE [dbo].[Fruits](
        [FruitId] [int] IDENTITY(1,1) NOT NULL,
        [BasketId] [int] NOT NULL,
        [FruitName] [varchar](50) NOT NULL,
     CONSTRAINT [PK_Fruits] PRIMARY KEY CLUSTERED 
        (
            [FruitId] ASC
        )
    )
    
    ALTER TABLE [dbo].[Fruits]  WITH CHECK 
    ADD CONSTRAINT [FK_Fruits_Baskets] FOREIGN KEY([BasketId])
    REFERENCES [dbo].[Baskets] ([BasketId])
    ALTER TABLE [dbo].[Fruits] CHECK CONSTRAINT [FK_Fruits_Baskets]
    
    --Properties
    CREATE TABLE [dbo].[Properties](
        [PropertyId] [int] IDENTITY(1,1) NOT NULL,
        [FruitId] [int] NOT NULL,
        [PropertyText] [varchar](50) NOT NULL,
     CONSTRAINT [PK_Properties] PRIMARY KEY CLUSTERED 
        (
            [PropertyId] ASC
        )
    )
    
    ALTER TABLE [dbo].[Properties]  WITH CHECK 
    ADD CONSTRAINT [FK_Properties_Fruits] FOREIGN KEY([FruitId])
    REFERENCES [dbo].[Fruits] ([FruitId])
    
    ALTER TABLE [dbo].[Properties] CHECK CONSTRAINT [FK_Properties_Fruits]
    
    -------------------------
    --Fill tables with data--
    -------------------------
    SET IDENTITY_INSERT [dbo].[Baskets] ON 
    GO
    INSERT [dbo].[Baskets] ([BasketId], [BasketName]) VALUES (1, N'Home Basket')
    GO
    SET IDENTITY_INSERT [dbo].[Baskets] OFF
    GO
    SET IDENTITY_INSERT [dbo].[Fruits] ON 
    GO
    INSERT [dbo].[Fruits] ([FruitId], [BasketId], [FruitName]) VALUES (1, 1, N'Apple')
    GO
    INSERT [dbo].[Fruits] ([FruitId], [BasketId], [FruitName]) VALUES (2, 1, N'Orange')
    GO
    SET IDENTITY_INSERT [dbo].[Fruits] OFF
    GO
    SET IDENTITY_INSERT [dbo].[Properties] ON 
    GO
    INSERT [dbo].[Properties] ([PropertyId], [FruitId], [PropertyText]) VALUES (1, 2, N'is juicy')
    GO
    INSERT [dbo].[Properties] ([PropertyId], [FruitId], [PropertyText]) VALUES (2, 2, N'hard to peel')
    GO
    INSERT [dbo].[Properties] ([PropertyId], [FruitId], [PropertyText]) VALUES (3, 1, N'is red')
    GO
    SET IDENTITY_INSERT [dbo].[Properties] OFF
    GO
    
    
    --------------------------------------------------------------
    -- Copy 'Home Basket' to new basket named 'COPY BASKET' --
    -- i.e., Copy Basket (and all fruits and their fruit properties) having basket id 
    -- @origBasketId to a new basket with name 'COPY BASKET'.
    --------------------------------------------------------------
    DECLARE @originalBasket int
    select @originalBasket = 1
    
    begin tran
    
    INSERT INTO BASKETS(BASKETNAME)
    VALUES ('COPY BASKET')
    
    DECLARE @newBasketId int
    SET @newBasketId = SCOPE_IDENTITY();
    
    insert into Fruits (BasketId, FruitName)
    select @newBasketId, FruitName
    from Fruits
    where BasketId = @originalBasket
    
    declare @tabFruit table (originalFruitId int, newFruitId int)
    
    insert into @tabFruit (originalFruitId, newFruitId)
    select o.FruitId, n.FruitId
    from (SELECT FruitId, FruitName from Fruits where BasketId = @originalBasket) as o
    join (SELECT FruitId, FruitName from Fruits where BasketId = @newBasketId) as n
        on o.FruitName = n.FruitName --if your table equivalent to Fruits has other fields, match on those as well here.
    
    insert into Properties (FruitId, PropertyText)
    select NewFruitId, PropertyText
    from Properties p join @tabFruit t on t.originalFruitId = p.FruitId
    
    commit tran
    
    ---------------
    --See results--
    ---------------
    select * 
    from dbo.Baskets b inner join dbo.Fruits f on b.BasketId=f.BasketId 
     inner join properties p on p.FruitId=f.FruitId
     order by b.BasketId, f.FruitId, p.PropertyId
    

提交回复
热议问题