2016-08-18 8 views
1

Мне было предложено найти наиболее эффективный способ ввода ввода DataTable и записать его в таблицу SQL Server с помощью C#. Недостатком является то, что решение должно использовать ODBC Connections во всем, это исключает sqlBulkCopy. Решение также должно работать на всех версиях SQL Server обратно в SQL Server 2008 R2.Пакетная вставка в таблицу SQL Server из DataTable с использованием соединения ODBC

Я имею в виду, что лучший подход должен был бы использовать пакетные вставки 1000 строк в то время, используя следующий синтаксис: SQL

INSERT INTO dbo.Table1 (Field1, Field2) ВЫБРАТЬ Value1, Value2 UNION 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; 
     } 
    } 

Любые советы будут оценены. Кроме того, если есть более простой подход, чем тот, который я предлагаю, любые детали этого были бы замечательными.

+0

Вы также исключаете параметры таблицы ADO.net? Это странное ограничение, поскольку передача параметра таблицы в хранимую процедуру и использование команды MERGE на входящей таблице на сегодняшний день является наиболее эффективным способом достижения этого. – PhillipH

+0

Проблема в том, что у нас будут очень ограниченные права на SQL Server, на которые мы пишем. У нас есть CRUD на столах, и об этом.Любое решение, связанное с сохраненными процессами и/или TVP, не распространяется, насколько я боюсь. –

ответ

2

Хорошо, поскольку мы не можем использовать хранимые процедуры или Массовую копию; когда я моделировал различные подходы пару лет назад, ключевым фактором, определяющим производительность, было количество вызовов на сервер. Таким образом, было установлено, что пакетный набор операторов 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()); 

Вам нужно иметь дело с осложнениями размера партии и форматирование правильных типов данных поля в строке шаг за шагом, но в противном случае это будет лучшая производительность.

+0

Можете ли вы разделить код, который вы использовали для сборки операторов SQL в партиях? Вот где я сейчас застрял. –

+0

Большое спасибо, это здорово. –

1

Помечено решение проблемы с PhillipH открыто для нескольких ошибок и SQL-инъекций.

Как правило, вы должны создать DbCommand с параметрами и выполнить это вместо выполнения инструкции self build SQL.

Командный текст должен быть "INSERT INTO Tab1 VALUES ?,?,?" для ODBC и OLEDB, SqlClient нужны именованные параметры ("@ < Название >").

Параметры должны быть добавлены с размерами подкладочной колонны.

 Смежные вопросы

  • Нет связанных вопросов^_^