[c#] How to insert a data table into SQL Server database table?

I have imported data from some Excel file and I have saved it into a datatable. Now I'd like to save this information in my SQL Server database.

I saw a lot of information on the web but I cannot understand it:

  1. Someone said insert line by line another suggested bulk update... etc: what it better?
  2. Should I use OLE or SQL Server objects (like dataAdapter or connection)?

My need is to read the employee weekly hours report, from his Excel file and save it to a database table where all the reports are saved (updating the db with new records every week).

The Excel file contains reports only for the current week.

This question is related to c# sql-server datatable

The answer is


I would suggest you go for bulk insert as suggested in this article : Bulk Insertion of Data Using C# DataTable and SQL server OpenXML function


If it's the first time for you to save your datatable

Do this (using bulk copy). Assure there are no PK/FK constraint

SqlBulkCopy bulkcopy = new SqlBulkCopy(myConnection);
//I assume you have created the table previously
//Someone else here already showed how  
bulkcopy.DestinationTableName = table.TableName;
try                             
{                                 
    bulkcopy.WriteToServer(table);                            
}     
    catch(Exception e)
{
    messagebox.show(e.message);
} 

Now since you already have a basic record. And you just want to check new record with the existing one. You can simply do this.

This will basically take existing table from database

DataTable Table = new DataTable();

SqlConnection Connection = new SqlConnection("ConnectionString");
//I assume you know better what is your connection string

SqlDataAdapter adapter = new SqlDataAdapter("Select * from " + TableName, Connection);

adapter.Fill(Table);

Then pass this table to this function

public DataTable CompareDataTables(DataTable first, DataTable second)
{
    first.TableName = "FirstTable";
    second.TableName = "SecondTable";

    DataTable table = new DataTable("Difference");

    try
    {
        using (DataSet ds = new DataSet())
        {
            ds.Tables.AddRange(new DataTable[] { first.Copy(), second.Copy() });

            DataColumn[] firstcolumns = new DataColumn[ds.Tables[0].Columns.Count];

            for (int i = 0; i < firstcolumns.Length; i++)
            {
                firstcolumns[i] = ds.Tables[0].Columns[i];
            }

            DataColumn[] secondcolumns = new DataColumn[ds.Table[1].Columns.Count];

            for (int i = 0; i < secondcolumns.Length; i++)
            {
                secondcolumns[i] = ds.Tables[1].Columns[i];
            }

            DataRelation r = new DataRelation(string.Empty, firstcolumns, secondcolumns, false);

            ds.Relations.Add(r);

            for (int i = 0; i < first.Columns.Count; i++)
            {
                table.Columns.Add(first.Columns[i].ColumnName, first.Columns[i].DataType);
            }

            table.BeginLoadData();

            foreach (DataRow parentrow in ds.Tables[0].Rows)
            {
                DataRow[] childrows = parentrow.GetChildRows(r);
                if (childrows == null || childrows.Length == 0)
                    table.LoadDataRow(parentrow.ItemArray, true);
            }

            table.EndLoadData();

        }
    }

    catch (Exception ex)
    {
        throw ex;
    }

    return table;
}

This will return a new DataTable with the changed rows updated. Please ensure you call the function correctly. The DataTable first is supposed to be the latest.

Then repeat the bulkcopy function all over again with this fresh datatable.


I found that it was better to add to the table row by row if your table has a primary key. Inserting the entire table at once creates a conflict on the auto increment.

Here's my stored Proc

CREATE PROCEDURE dbo.usp_InsertRowsIntoTable
@Year       int,
@TeamName   nvarchar(50),
AS
INSERT INTO [dbo.TeamOverview]
(Year,TeamName)
VALUES (@Year, @TeamName);
RETURN

I put this code in a loop for every row that I need to add to my table:

insertRowbyRowIntoTable(Convert.ToInt16(ddlChooseYear.SelectedValue), name);

And here is my Data Access Layer code:

        public void insertRowbyRowIntoTable(int ddlValue, string name)
    { 
        SqlConnection cnTemp = null;
        string spName = null;
        SqlCommand sqlCmdInsert = null;

        try
        {
            cnTemp = helper.GetConnection();
            using (SqlConnection connection = cnTemp)
            {
                if (cnTemp.State != ConnectionState.Open)
                    cnTemp.Open();
                using (sqlCmdInsert = new SqlCommand(spName, cnTemp))
                {
                    spName = "dbo.usp_InsertRowsIntoOverview";
                    sqlCmdInsert = new SqlCommand(spName, cnTemp);
                    sqlCmdInsert.CommandType = CommandType.StoredProcedure;

                    sqlCmdInsert.Parameters.AddWithValue("@Year", ddlValue);
                    sqlCmdInsert.Parameters.AddWithValue("@TeamName", name);

                    sqlCmdInsert.ExecuteNonQuery();

                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            if (sqlCmdInsert != null)
                sqlCmdInsert.Dispose();

            if (cnTemp.State == ConnectionState.Open)
                cnTemp.Close();
        }

    }

public bool BulkCopy(ExcelToSqlBo objExcelToSqlBo, DataTable dt, SqlConnection conn, SqlTransaction tx)
{
    int check = 0;
    bool result = false;
    string getInsert = "";
    try
    {
        if (dt.Rows.Count > 0)
        {
            foreach (DataRow dr in dt.Rows)
            {
                if (dr != null)
                {
                    if (check == 0)
                    {
                        getInsert = "INSERT INTO [tblTemp]([firstName],[lastName],[Father],[Mother],[Category]" +
                                ",[sub_1],[sub_LG2])"+
                                " select '" + dr[0].ToString() + "','" + dr[1].ToString() + "','" + dr[2].ToString() + "','" + dr[3].ToString() + "','" + dr[4].ToString().Trim() + "','" + dr[5].ToString().Trim() + "','" + dr[6].ToString();

                        check += 1;
                    }
                    else
                    {
                        getInsert += " UNION ALL ";

                        getInsert += " select  '" + dr[0].ToString() + "','" + dr[1].ToString() + "','" + dr[2].ToString() + "','" + dr[3].ToString() + "','" + dr[4].ToString().Trim() + "','" + dr[5].ToString().Trim() + "','" + dr[6].ToString() ;

                        check++;
                    }
                }
            }
            result = common.ExecuteNonQuery(getInsert, DatabasesName, conn, tx);
        }
        else
        {
            throw new Exception("No row for insertion");
        }
        dt.Dispose();
    }
    catch (Exception ex)
    {
        dt.Dispose();
        throw new Exception("Please attach file in Proper format.");
    }
    return result;
} 

    //best way to deal with this is sqlbulkcopy 
    //but if you dont like it you can do it like this
    //read current sql table in an adapter
    //add rows of datatable , I have mentioned a simple way of it
    //and finally updating changes

    Dim cnn As New SqlConnection("connection string")        
    cnn.Open()
    Dim cmd As New SqlCommand("select * from  sql_server_table", cnn)
    Dim da As New SqlDataAdapter(cmd)       
    Dim ds As New DataSet()
    da.Fill(ds, "sql_server_table")
    Dim cb As New SqlCommandBuilder(da)        

    //for each datatable row
    ds.Tables("sql_server_table").Rows.Add(COl1, COl2)

    da.Update(ds, "sql_server_table")

From my understanding of the question,this can use a fairly straight forward solution.Anyway below is the method i propose ,this method takes in a data table and then using SQL statements to insert into a table in the database.Please mind that my solution is using MySQLConnection and MySqlCommand replace it with SqlConnection and SqlCommand.

public void InsertTableIntoDB_CreditLimitSimple(System.Data.DataTable tblFormat)
    {
        for (int i = 0; i < tblFormat.Rows.Count; i++)
        {

            String InsertQuery = string.Empty;

            InsertQuery = "INSERT INTO customercredit " +
                          "(ACCOUNT_CODE,NAME,CURRENCY,CREDIT_LIMIT) " +
                          "VALUES ('" + tblFormat.Rows[i]["AccountCode"].ToString() + "','" + tblFormat.Rows[i]["Name"].ToString() + "','" + tblFormat.Rows[i]["Currency"].ToString() + "','" + tblFormat.Rows[i]["CreditLimit"].ToString() + "')";



            using (MySqlConnection destinationConnection = new MySqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ToString()))
            using (var dbcm = new MySqlCommand(InsertQuery, destinationConnection))
            {
                destinationConnection.Open();
                dbcm.ExecuteNonQuery();
            }
        }
    }//CreditLimit

I am giving a very simple code, which i used in my solution (I have the same problem statement as yours)

    SqlConnection con = connection string ;
//new SqlConnection("Data Source=.;uid=sa;pwd=sa123;database=Example1");
con.Open();
string sql = "Create Table abcd (";
foreach (DataColumn column in dt.Columns)
{
    sql += "[" + column.ColumnName + "] " + "nvarchar(50)" + ",";
}
sql = sql.TrimEnd(new char[] { ',' }) + ")";
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
cmd.ExecuteNonQuery();
using (var adapter = new SqlDataAdapter("SELECT * FROM abcd", con)) 
using(var builder = new SqlCommandBuilder(adapter))
{
adapter.InsertCommand = builder.GetInsertCommand();
adapter.Update(dt);
// adapter.Update(ds.Tables[0]); (Incase u have a data-set)
}
con.Close();

I have given a predefined table-name as "abcd" (you must take care that a table by this name doesn't exist in your database). Please vote my answer if it works for you!!!! :)


Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to sql-server

Passing multiple values for same variable in stored procedure SQL permissions for roles Count the Number of Tables in a SQL Server Database Visual Studio 2017 does not have Business Intelligence Integration Services/Projects ALTER TABLE DROP COLUMN failed because one or more objects access this column Create Local SQL Server database How to create temp table using Create statement in SQL Server? SQL Query Where Date = Today Minus 7 Days How do I pass a list as a parameter in a stored procedure? SQL Server date format yyyymmdd

Examples related to datatable

Can't bind to 'dataSource' since it isn't a known property of 'table' How to get a specific column value from a DataTable in c# Change Row background color based on cell value DataTable How to bind DataTable to Datagrid Find row in datatable with specific id Datatable to html Table How to Edit a row in the datatable How do I use SELECT GROUP BY in DataTable.Select(Expression)? How to fill a datatable with List<T> SqlBulkCopy - The given value of type String from the data source cannot be converted to type money of the specified target column