簡體   English   中英

使用ODBC連接從DataTable批量插入SQL Server表

[英]Batch insert to SQL Server table from DataTable using ODBC Connection

我被要求尋找最有效的方法來獲取DataTable輸入並使用C#將其寫入SQL Server表。 問題在於解決方案必須始終使用ODBC連接,這排除了sqlBulkCopy。 該解決方案還必須適用於SQL Server 2008 R2的所有SQL Server版本。

我認為最好的方法是使用以下SQL語法一次使用1000行的批量插入:

INSERT INTO dbo.Table1(Field1,Field2)SELECT Value1,Value2 UNION SELECT Value1,Value2

我已經編寫了代碼,檢查SQL Server上是否已存在與DataTable輸入相對應的表,如果不存在則創建一個表。

我還編寫了代碼來創建INSERT語句本身。 我正在努力的是如何從數據表中的行動態構建SELECT語句。 如何訪問行中的值以構建我的SELECT語句? 我想我還需要檢查每列的數據類型,以確定值是否需要用單引號(')括起來。

這是我目前的代碼:

        public bool CopyDataTable(DataTable sourceTable, OdbcConnection targetConn, string targetTable)
    {
        OdbcTransaction tran = null;
        string[] selectStatement = new string[sourceTable.Rows.Count];

        // Check if targetTable exists, create it if it doesn't
        if (!TableExists(targetConn, targetTable))
        {
            bool created = CreateTableFromDataTable(targetConn, sourceTable);

            if (!created)
                return false;
        }

        try
        {
            // Prepare insert statement based on sourceTable
            string insertStatement = string.Format("INSERT INTO [dbo].[{0}] (", targetTable);

            foreach (DataColumn dataColumn in sourceTable.Columns)
            {
                insertStatement += dataColumn + ",";
            }

            insertStatement += insertStatement.TrimEnd(',') + ") ";

            // Open connection to target db
            using (targetConn)
            {
                if (targetConn.State != ConnectionState.Open)
                    targetConn.Open();

                tran = targetConn.BeginTransaction();

                for (int i = 0; i < sourceTable.Rows.Count; i++)
                {
                    DataRow row = sourceTable.Rows[i];

                    // Need to iterate through columns in row, getting values and data types and building a SELECT statement

                    selectStatement[i] = "SELECT ";
                }

                insertStatement += string.Join(" UNION ", selectStatement);

                using (OdbcCommand cmd = new OdbcCommand(insertStatement, targetConn, tran))
                {
                    cmd.ExecuteNonQuery();
                }

                tran.Commit();
                return true;
            }
        }       
        catch 
        {
            tran.Rollback();
            return false;
        }
    }

任何建議將不勝感激。 此外,如果有一個比我建議的更簡單的方法,那么任何細節都會很棒。

好的,因為我們不能使用存儲過程或批量復制; 幾年前,當我模擬各種方法時,性能的關鍵決定因素是對服務器的調用次數。 因此,將一組MERGE或INSERT語句批處理為由分號分隔的單個調用被發現是最快的方法。 我最終批處理我的SQL語句。 我認為SQL語句的最大大小是32k所以我把我的批量切成了那個大小的單位。

(注意 - 使用StringBuilder而不是手動連接字符串 - 它對性能有益)

Psuedo-code
string sqlStatement = "INSERT INTO Tab1 VALUES {0},{1},{2}";
StringBuilder sqlBatch = new StringBuilder();
foreach(DataRow row in myDataTable)
{
    sqlBatch.AppendLine(string.Format(sqlStatement, row["Field1"], row["Field2"], row["Field3"]));
    sqlBatch.Append(";");
}
myOdbcConnection.ExecuteSql(sqlBatch.ToString());

您需要處理批量大小的復雜性,並在字符串替換步驟中格式化正確的字段數據類型,否則這將是最佳性能。

PhillipH的標記解決方案可以解決幾個錯誤和SQL注入問題。

通常,您應該使用參數構建DbCommand並執行此操作,而不是執行自構建SQL語句。

CommandText必須是"INSERT INTO Tab1 VALUES ?,?,?" 對於ODBC和OLEDB,SqlClient需要命名參數(“@ <Name>”)。

應使用下墊列的尺寸添加參數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM