SQL批量复制YYYYMMDD问题

发布于 2024-10-13 15:26:00 字数 1307 浏览 6 评论 0 原文

我在 asp.net 3.5 中使用 SQL Bulkcopy 和 C# 遇到字符串到日期转换问题

我读取了一个大型 CSV 文件(带有 CSV 阅读器)。读取的字符串之一应加载到 SQL Server 2008 日期列中。

例如,如果文本文件包含字符串“2010-12-31”,SQL Bulkcopy 会将其加载到“日期”列中,不会出现任何问题。

但是,如果字符串是“20101231”,则会收到错误:
数据源中String类型的给定值无法转换为指定目标列的date类型

该文件包含8000万条记录,因此无法创建数据表....

SqlBulkcopy Columnmappings等都是好的。更改为 DateTime 也没有帮助。

我尝试过

SET DATEFORMAT ymd;

但这没有帮助。

有什么想法如何告诉 SQL Server 接受这种格式吗?否则,我将在 CSV 阅读器中创建自定义修复,但我更喜欢 SQL 中的内容。

更新 根据这两个答案,我正在使用这样的 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' 

它也可以工作,只是不能使用批量复制。

知道为什么吗?

感谢您的任何建议, 普伦

I have a String to Date conversion problem using SQL Bulkcopy in asp.net 3.5 with C#

I read a large CSV file (with CSV reader). One of the strings read should be loaded into a SQL server 2008 Date column.

If the textfile contains for example the string '2010-12-31', SQL Bulkcopy loads it without any problems into the Date column.

However, if the string is '20101231', I get an error:
The given value of type String from the data source cannot be converted to type date of the specified target column

The file contains 80 million records so I cannot create a datatable....

SqlBulkcopy Columnmappings etc. are all ok. Also changing to DateTime does not help.

I tried

SET DATEFORMAT ymd;

But that does not help.

Any ideas how to tell SQL Server to accept this format? Otherwise I will create a custom fix in CSV reader but I would prefer something in SQL.

update
Following up on the two answers, I am using SQL bulkcopy like this (as proposed on Stackoverflow in another question):

The CSV reader (see the link above on codeproject) returns string values (not strong typed). The CSVreader implements System.Data.IDataReader so I can do something like this:

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

All the fields coming from the iDataReader are strings, so I cannot use the c# approach unless I change quite a bit in the CSVreader

My question is therefore not related on how to fix it in C#, I can do that but i want to prevent that.

It is strange, because if you do a in sql something like

 update set [somedatefield] = '20101231' 

it also works, just not with bulkcopy.

Any idea why?

Thanks for any advice,
Pleun

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

以歌曲疗慰 2024-10-20 15:26:00

较旧的问题,但想添加一种替代方法。

我遇到了同样的问题,即 SQLBulkLoader 在从 IDataReader 流式传输时不允许列的数据类型/区域性规范。

为了减少在本地构建数据行的速度开销,并在目标上进行解析,我使用的一个简单方法是临时将线程区域性设置为定义所使用格式的区域性 - 在本例中为美国格式日期。

对于我的问题 - 输入中的 en-US 日期(在 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 接口就执行类型转换,这比在本地执行解析要快得多,尤其是在脚本语言中。

Older issue, but wanted to add an alternative approach.

I had the same issue with SQLBulkLoader not allowing DataType/culture specifications for columns when streaming from IDataReader.

In order to reduce the speed overhead of constructing datarows locally and instead have the parsing occur on the target, a simple method I used was to temporarily set the thread culture to the culture which defines the format in use - in this case for US format dates.

For my problem - en-US dates in the input (in Powershell):

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

For your problem, you could do the same but since the date format is not culture specific, create a default culture object (untested):

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

I found allowing the database server to perform the type conversions once they've gotten through the SQLBulkCopy interface to be considerably faster than performing parsing locally, particularly in a scripting language.

习惯那些不曾习惯的习惯 2024-10-20 15:26:00

如果您可以在 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);
}

它不是完整的代码,但我认为你可以解决它...

If you can handel it in C# itself then this code will help get the date in the string as a DateTime object which you can pass directly

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

If you want it to be formatted as string then:

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

Good luck.

Update

In your scenario i don't know why date is not automatically formatted but from C# you need to get in and Interfere in the process of passing the data to the WriteToServer() method. Best i think you can do (keeping in mind the Performance) is to have a cache of DataRow items and Pass them to the WriteToServer() method. I will just write the sample code in a minute...

//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);
}

Its not full code but i think you can work it out...

梦初启 2024-10-20 15:26:00

目前尚不完全清楚如何使用 SqlBulkCopy,但理想情况下,您根本不应该以字符串格式将数据上传到 SQL Server:将其解析为 DateTime 或CSV 阅读器(或 CSV 阅读器的输出)中的 DateTimeOffset 并以这种方式上传。那么你就不需要担心字符串格式。

It's not entirely clear how you're using SqlBulkCopy, but ideally you shouldn't be uploading the data to SQL Server in string format at all: parse it to a DateTime or DateTimeOffset in your CSV reader (or on the output of your CSV reader), and upload it that way. Then you don't need to worry about string formats.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文