Avoiding a cursor when copying a master-detail structure

  • If you have a 1->M table relationship, between tblMaster and tblChild table, how can you best write a stored proc that will move those records to another set of tables like prod.tblMaster and prod.tblChild

    The solution I have right now is to cursor through the master table, do an insert to the new table and get the identity key, and then do a insert into the child prod.tblChild table

    I would like to change this is possible - I can have a large number of records in the tblChild tables and the cursor method is really slow.

    Thanks!

  • You could simply run:

    INSERT INTO prob.tblMaster SELECT * FROM tblMaster

    INSERT INTO prob.tblChild SELECT * FROM tblChild

  • Sorry, I didn't notice that the connection was based on an identity column.

    In this case try the following:

    ALTER TABLE prod.tblMaster ADD PrevID BIGINT -- Or whatever

    INSERT INTO

    prod.tblMaster

    SELECT

    tblMaster.Column1,

    tblMaster.Column2,

    ... -- All columns but ID

    tblMaster.ID AS PrevID FROM tblMaster

    FROM

    tblMaster

    INSERT INTO

    prob.tblChild

    SELECT

    tblChild.Column1,

    tblChild.Column2,

    ... -- All except ID,

    prob.tblMaster.ID AS ID

    FROM

    tblChild

    INNER JOIN prob.tblMaster.ID

    ON tblChild.ID = prob.tblMaster.PrevID

    ALTER TABLE prod.tblMaster DROP COLUMN PrevID

  • if you go for the above solution, you'll need to do some extra work afterwards. Here's why.

    Regards,

    Willem
    http://wschampheleer.wordpress.com[/url]

  • You could try using the Switch command.

    ALTER TABLE [dbo].tbl1 SWITCH to [dbo].tbl2

  • Another option is to use the OUTPUT clause to capture the generated ID's and then use them in the inserts in the second table.

    "The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
    - Theodore Roosevelt

    Author of:
    SQL Server Execution Plans
    SQL Server Query Performance Tuning

  • sql_lock (2/10/2010)


    You could try using the Switch command.

    ALTER TABLE [dbo].tbl1 SWITCH to [dbo].tbl2

    Don't you also have to set up partitioning between these tables first? I'm asking because I've never used the SWITCH function.

    "The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
    - Theodore Roosevelt

    Author of:
    SQL Server Execution Plans
    SQL Server Query Performance Tuning

  • A modified version after Willem's note (thanks Willem):

    INSERT INTO

    prod.tblMaster

    OUTPUT

    INSERTED.ID AS ID,

    tblMaster.ID AS PrevID

    INTO #t

    SELECT

    *

    FROM

    tblMaster

    INSERT INTO

    prob.tblChild

    SELECT

    tblChild.Column1,

    tblChild.Column2,

    ... -- All except ID,

    #t.ID AS ID

    FROM

    tblChild

    INNER JOIN #t

    ON tblChild.ID = #t.PrevID

    Hope it runs

  • Grant,

    In my example, no (as sql is just changes the pointers to the meta-data). But to answer with the original post in mind then yes you would need to setup some pre-req's 1st.

    i.e

    Same filegroup must be used, partition must exist etc etc

    The Article on MSDN give you futher details..

    http://technet.microsoft.com/en-us/library/ms191160.aspx

  • sql_lock (2/10/2010)


    Grant,

    In my example, no (as sql is just changes the pointers to the meta-data). But to answer with the original post in mind then yes you would need to setup some pre-req's 1st.

    i.e

    Same filegroup must be used, partition must exist etc etc

    The Article on MSDN give you futher details..

    http://technet.microsoft.com/en-us/library/ms191160.aspx

    Good article and a neat trick. Thanks.

    "The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
    - Theodore Roosevelt

    Author of:
    SQL Server Execution Plans
    SQL Server Query Performance Tuning

  • pink_panther,

    Thank you for the compliment.

    Unfortunately, I believe your new version is no improvement: you still need to insert the old ID if you want to retrieve it using the OUTPUT option...

    Regards,

    Willem
    http://wschampheleer.wordpress.com[/url]

  • wschampheleer (2/10/2010)


    pink_panther,

    Thank you for the compliment.

    Unfortunately, I believe your new version is no improvement: you still need to insert the old ID if you want to retrieve it using the OUTPUT option...

    No, the OUTPUT function will get the ID generated by the insert. That's the biggest beauty of it.

    "The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
    - Theodore Roosevelt

    Author of:
    SQL Server Execution Plans
    SQL Server Query Performance Tuning

  • Grant Fritchey (2/10/2010)


    wschampheleer (2/10/2010)


    pink_panther,

    Thank you for the compliment.

    Unfortunately, I believe your new version is no improvement: you still need to insert the old ID if you want to retrieve it using the OUTPUT option...

    No, the OUTPUT function will get the ID generated by the insert. That's the biggest beauty of it.

    Grant,

    I am familiar with the OUTPUT clause. however, the problem that I see is that you need to be able to relate the generated ID to the ID in the old table so you can join it to the old details table. I have the impression that this is not going to work in pink_panther's solution.

    Regards,

    Willem
    http://wschampheleer.wordpress.com[/url]

  • wschampheleer (2/10/2010)


    Grant Fritchey (2/10/2010)


    wschampheleer (2/10/2010)


    pink_panther,

    Thank you for the compliment.

    Unfortunately, I believe your new version is no improvement: you still need to insert the old ID if you want to retrieve it using the OUTPUT option...

    No, the OUTPUT function will get the ID generated by the insert. That's the biggest beauty of it.

    Grant,

    I am familiar with the OUTPUT clause. however, the problem that I see is that you need to be able to relate the generated ID to the ID in the old table so you can join it to the old details table. I have the impression that this is not going to work in pink_panther's solution.

    Possibly true. I'm making the (probably erroneous) assumption that there is a natural key to allow for identifying the values in addition to the ID.

    "The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
    - Theodore Roosevelt

    Author of:
    SQL Server Execution Plans
    SQL Server Query Performance Tuning

  • Thank you all for some great ideas. The output clause is soooo close to what I need, but not quite. Of the solutions offered:

    1) I can't use the switch because I am appending records from my source table to my destination table, not moving an entire table. A switch would wipe out my old records in my destination table

    2) The ouptut option as described by pink_panther has the flaw that the output parameters on the insert only sees the columns being inserted. Thus the need to have a place to stick the prevID during the insert. That is why the other solution had an Alter Table to add the prevID. So, I either have to Alter the table everytime I append something or always have the previousID as a column in my tables. Since I can't be altering a particularly large table and incurring the locks on my prod tables, that leaves me with changing my standard to have a prevID defined in my tables that I use solely for copying records.

    Unless there are any other ideas, I may have to either stick to a cursor for this type of project or re-architect many of my tables....

Viewing 15 posts - 1 through 15 (of 20 total)

You must be logged in to reply to this topic. Login to reply