使用ODBC连接从DataTable批量插入到SQL Server表

本文关键字:插入 SQL Server ODBC 连接 DataTable 使用 | 更新日期: 2023-09-27 18:02:49

我被要求寻找最有效的方法来获取数据表输入并使用c#将其写入SQL Server表。问题是解决方案必须始终使用ODBC连接,这就排除了sqlBulkCopy。该解决方案还必须适用于SQL Server 2008 R2之前的所有SQL Server版本。

我认为最好的方法是使用以下SQL语法一次批量插入1000行:

INSERT INTO dbo。表1 (Field1, Field2)SELECT Value1, Value2联盟SELECT Value1, Value2

我已经写了代码,检查与DataTable输入相对应的表是否已经存在于SQL Server上,如果不存在则创建一个。

我还编写了创建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;
        }
    }

如有任何建议将不胜感激。此外,如果有比我建议的更简单的方法,那么任何细节都将是伟大的。

使用ODBC连接从DataTable批量插入到SQL Server表

既然我们不能使用存储过程或批量复制;几年前,当我对各种方法建模时,性能的关键决定因素是对服务器的调用次数。因此,将一组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对于ODBC和OLEDB必须是"INSERT INTO Tab1 VALUES ?,?,?", SqlClient需要命名参数("@")

参数应加上底层列的尺寸