SQL Bulkcopy YYYYMMDD проблема - PullRequest
       8

SQL Bulkcopy YYYYMMDD проблема

2 голосов
/ 20 января 2011

У меня проблема с преобразованием строки в дату с использованием SQL Bulkcopy в asp.net 3.5 с C #

Я читаю большой файл CSV (с Читатель CSV ).Одна из прочитанных строк должна быть загружена в столбец Date SQL Server 2008.

Если текстовый файл содержит, например, строку «2010-12-31», SQL Bulkcopy без проблем загружает ее в столбец Date.

Однако, если строка '20101231', я получаю сообщение об ошибке:
Указанное значение типа String из источника данных не может быть преобразовано в дату типа указанного целевого столбца

Файл содержит 80 миллионов записей, поэтому я не могу создать таблицу данных ....

SqlBulkcopy Столбцы и т. Д. Все в порядке.Также изменение DateTime не помогает.

Я пытался

SET DATEFORMAT ymd;

Но это не помогает.

Есть идеи, как заставить SQL Server принять этот формат?В противном случае я создам собственное исправление в программе чтения CSV, но я бы предпочел что-то в SQL.

update Следуя двум ответам, я использую массовую копию SQL, как это (как предложено в Stackoverflow)в другом вопросе):

Программа чтения CSV (см. ссылку выше на codeproject) возвращает строковые значения (не строго типизированные).CSVreader реализует System.Data.IDataReader, так что я могу сделать что-то вроде этого:

using (CsvReader reader = new CsvReader(path)) 
using (SqlBulkCopy bcp = new SqlBulkCopy(CONNECTION_STRING))
{ bcp.DestinationTableName = "SomeTable"; 
  // columnmappings
  bcp.WriteToServer(reader); } 

Все поля, поступающие из iDataReader, являются строками, поэтому я не могу использовать подход c #, если я немного не изменю вCSVreader

Поэтому мой вопрос не связан с тем, как это исправить в C #, я могу это сделать, но я хочу предотвратить это.

Это странно, потому что если вы что-то делаете в sqlкак

 update set [somedatefield] = '20101231' 

это также работает, только не с помощью массового копирования.

Есть идеи почему?

Спасибо за любой совет, Pleun

Ответы [ 3 ]

2 голосов
/ 20 января 2011

Если вы можете обработать его в самом C #, тогда этот код поможет получить дату в строке в виде объекта DateTime, которую вы можете передать напрямую

//datestring is the string read from CSV
DateTime thedate = DateTime.ParseExact(dateString, "yyyyMMdd", null);

Если вы хотите, чтобы она была отформатирована как строка, тогда:

string thedate = DateTime.ParseExact(dateString, "yyyyMMdd", null).ToString("yyyy-MM-dd");

Удачи.

Обновление

В вашем сценарии я не знаю, почему дата не форматируется автоматически, а из C # вынеобходимо войти и вмешиваться в процесс передачи данных в метод WriteToServer().Лучшее, что я думаю, что вы можете сделать (имея в виду производительность) - это иметь кэш элементов DataRow и передавать их в метод WriteToServer () .Я просто напишу пример кода через минуту ...

//A sample code.. polish it before implementation
//A counter to track num of records read
long records_read = 0;
While(reader.Read())
{
    //We will take rows in a Buffer of 50 records
    int i = records_read;//initialize it with the num of records last read
    DataRow[] buffered_rows = new DataRow[50];
    for(;i<50 ;i++)
    {
        //Code to initialize each rows with the data in the reader
        //.....
        //Fill the column data with Date properly formatted
        records_read++;
        reader.Read();
    }
    bcp.WriteToServer(buffered_rows);
}

Это не полный код, но я думаю, что вы можете решить это ...

2 голосов
/ 12 мая 2014

Более старая проблема, но хотелось добавить альтернативный подход.

У меня была та же проблема с SQLBulkLoader, не позволяющим спецификации DataType / culture для столбцов при потоковой передаче из IDataReader.

Чтобы снизить накладные расходы на скорость создания datarows локально и вместо этого выполнить синтаксический анализ на целевом объекте, я использовал простой метод, чтобы временно установить культуру потоков в культуре, которая определяет используемый формат - в данном случае для Даты в американском формате.

Для моей проблемы - даты ввода в США (в Powershell):

[System.Threading.Thread]::CurrentThread.CurrentCulture = 'en-US'
<call SQLBulkCopy>

Для вашей проблемы вы можете сделать то же самое, но, поскольку формат даты не зависит от конкретной культуры, создайте объект культуры по умолчанию (непроверенный):

CultureInfo newCulture = (CultureInfo) System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
newCulture.DateTimeFormat.ShortDatePattern = "yyyyMMDD;
Thread.CurrentThread.CurrentCulture = newCulture;

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

0 голосов
/ 20 января 2011

Не совсем понятно, как вы используете SqlBulkCopy, но в идеале вам вообще не следует выгружать данные в SQL Server в строковом формате: проанализируйте их как DateTime или DateTimeOffset в программе чтения CSV(или на выходе вашего CSV-ридера), и загрузите его таким образом.Тогда вам не нужно беспокоиться о форматах строк.

...