3 records with same ID but change different columns using SqlBulkCopy

bulkinsert c# primary-key sqlbulkcopy

Question

I am doing a conversion with SqlBulkCopy. I currently have an IList collection of classes which basically i can do a conversion to a DataTable for use with SqlBulkCopy.

Problem is that I can have 3 records with the same ID.

Let me explain .. here are 3 records

ID      Name         Address
1       Scott        London
1       Mark         London
1                    Manchester

Basically i need to insert them sequentially .. hence i insert record 1 if it doesn't exist, then the next record if it exists i need to update the record rather than insert a new 1 (notice the id is still 1) so in the case of the second record i replace both columns Name And Address on ID 1.

Finally on the 3rd record you notice that Name doesn't exist but its ID 1 and has an address of manchester so i need to update the record but NOT CHANGING Name but updating Manchester.. hence the 3rd record would make the id1 =

ID      Name      Address
1       Mark      Manchester

Any ideas how i can do this? i am at a loss.

Thanks.

EDIT

Ok a little update. I will manage and merge my records before using SQLbulkCopy. Is it possible to get a list of what succeeded and what failed... or is it a case of ALL or nothing? I presume there is no other alternative to SQLbulkCopy but to do updates?

it would be ideal to be able to Insert everything and the ones that failed are inserted into a temp table ... hence i only need to worry about correcting the ones in my failed table as the others i know are all OK

Accepted Answer

Since you need to process that data into a DataTable anyway (unless you are writing a custom IDataReader), you should merge the records before giving them to SqlBulkCopy; for example (in pseudo code):

/* create empty data-table */
foreach(row in list) {
    var row = /* try to get exsiting row from data-table based on id */
    if(row == null) { row = /* create and append row to data-table */ }
    else { merge non-trivial properties into existing row */
}

then pass the DataTable to SqlBulkCopy once you have the desired data.


Re the edit; in that scenario, I would upload to a staging table (just a regular table that has a schema like the uploaded data, but typically no foreign keys etc), then use regular TSQL to move the data into the transactional tables. In addition to full TSQL support this also allows better logging of operations. In particular, perhaps look at the OUTPUT clause of INSERT which can help complex bulk operations.


Popular Answer

You can't do updates with bulk copy (bulk insert), only insert. Hence the name.

You need to fix the data before you insert them. If this means you have updates to pre-existing rows, you can't insert those as that will generate the key conflict.

You can either bulk insert into a temporary table, and run the appropriate insert or update statements, only insert the new rows and issue update statements for the rest, or delete the pre-existing rows after fetching them and fixing the data before reinserting.

But there's no way to persuade bulk copy to update an existing row.



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why