views:

1153

answers:

4

I have a SQLClient.DataSet in VB.NET, and I want to insert the entire thing into a SQL Server table without having to do the following:

For Each dr as Datarow in MyDataset
  Dim sc As New SqlCommand("INSERT INTO MyNewTable " & _
                            "VALUES (@column1, @column2)", MyDBConnection)
  sc.Parameters.AddWithValue("@column1", dr.Item(0))
  sc.Parameters.AddWithValue("@column2", dr.Item(1))
  sc.ExecuteNonQuery()
Next

Since I've got close to a million rows (all pretty skinny, so it's not much space), I obviously don't want to run this loop and generate a million INSERT statements.

I know that one option is to use a linked server when I initially fetch the data, since it's coming from another SQL Server, and just have it to the INSERT from there. However, if I already have the data in my application, is there a more efficient way to bulk insert it? Can I somehow pass the DataTable as a parameter to SQL Server and have it sort it out and insert the rows?

+9  A: 

try with SqlBulkCopy

anishmarokey
This looks to be exactly what I wanted. I had no idea this class even existed - thanks!
rwmnau
It inserted all one million records in about four seconds - that's perfect. Thanks again!
rwmnau
+2  A: 

You could call .WriteXML() on the DataSet and dump that into the database in one insert.

CSharpAtl
+1  A: 

Use the SqlDataAdapter's InsertCommand to define your Insert query. Then call the DataAdapter's Update Method with your dataset as a parameter to have it push the data.

Something like:

Dim DA As SqlDataAdapter = New SqlDataAdapter
Dim Parm As New SqlParameter

DA.InsertCommand = New SqlCommand("Insert Into tbl1(fld0, fld1, fld2) Values(@fld0, @fld1, @fld2)", conn)
Parm = DA.InsertCommand.Parameters.Add(New SqlParameter ("@fld0", NVarChar, 50, "fld0"))
Parm = sqlDA.InsertCommand.Parameters.Add(New SqlParameter ("@fld1", SqlDbType.NVarChar, 50, "fld1"))
Parm = sqlDA.InsertCommand.Parameters.Add(New SqlParameter ("@fld2", SqlDbType.NVarChar, 50, "fld2"))
DA.Update(dataset1, "tbl1")
C-Pound Guru
I considered this idea, but I think it still generates an INSERT statement for every row. At least it does it in the background, though, so it's cleaner for sure.
rwmnau
+3  A: 

With SQL Server 2008 you can use Table-Valued Parameters:

Dim sc As New SqlCommand(
  "INSERT INTO MyNewTable (field1, field2,...)"&
    "SELECT field1, field2,... FROM @MyTable;", MyDBConnection) 
sc.Parameters.AddWithValue("@MyTable", MyDataset)  
sc.ExecuteNonQuery()
Remus Rusanu
I happen to be using 2008, and that's an awesome idea! I wonder how the performance compares to SQLBulkCopy - I'm doing it over a gigabit LAN right now, but over a slower WAN connection, any idea of the comparison?
rwmnau
The performance will be driven by the transfer speed (client to server) and the differenc ein the amount of data between bulk copy and TVP is minimal, so they should behave similarly. Better measure.
Remus Rusanu