使用 SqlBulkCopy 插入数据时出错

Posted

技术标签:

【中文标题】使用 SqlBulkCopy 插入数据时出错【英文标题】:Error inserting data using SqlBulkCopy 【发布时间】:2010-11-04 16:07:18 【问题描述】:

我正在尝试使用 SqlBulkCopy 将数据批量插入 SQL 2008。

这是我的桌子:

IF OBJECT_ID(N'statement', N'U') IS NOT NULL
DROP TABLE [statement]
GO
CREATE TABLE [statement](
  [ID] INT IDENTITY(1, 1) NOT NULL,
  [date] DATE NOT NULL DEFAULT GETDATE(),
  [amount] DECIMAL(14,2) NOT NULL,
CONSTRAINT [PK_statement] PRIMARY KEY CLUSTERED
(
    [ID] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

这是我的代码:

private DataTable GetTable()

    var list = new List<DataColumn>();
    list.Add(new DataColumn("amount", typeof(SqlDecimal)));
    list.Add(new DataColumn("date", typeof(SqlDateTime)));

    var table = new DataTable("statement");
    table.Columns.AddRange(list.ToArray());

    var row = table.NewRow();
    row["amount"] = (SqlDecimal)myObj.Amount; // decimal Amount  get; set; 
    row["date"] = (SqlDateTime)myObj.Date; // DateTime Date  get; set 
    table.Rows.Add(row);

    return table;


private void WriteData()

    using (var bulk = new SqlBulkCopy(strConnection, SqlBulkCopyOptions.KeepIdentity & SqlBulkCopyOptions.KeepNulls))
    
        //table.Columns.ForEach(c => bulk.ColumnMappings.Add(new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)));
        bulk.BatchSize = 25;
        bulk.DestinationTableName = "statement";
        bulk.WriteToServer(GetTable()); // a table from GetTable() 
    

所以我得到了错误:

来自数据源的SqlDateTime类型的给定值无法转换为指定目标列的date类型。

为什么?我该如何解决?请帮帮我!

【问题讨论】:

【参考方案1】:

使用您的原始表格脚本,以下代码有效。

private static DataTable GetTable()

    var list = new List<DataColumn>();
    list.Add(new DataColumn("amount", typeof(Double)));
    list.Add(new DataColumn("date", typeof(DateTime)));
    var table = new DataTable("statement");
    table.Columns.AddRange(list.ToArray());

    var row = table.NewRow();
    row["amount"] = 1.2d;
    row["date"] = DateTime.Now.Date;

    table.Rows.Add(row);
    return table;

private static void WriteData()

    string strConnection = "Server=(local);Database=ScratchDb;Trusted_Connection=True;";
    using (var bulk = new SqlBulkCopy(strConnection, SqlBulkCopyOptions.KeepIdentity & SqlBulkCopyOptions.KeepNulls))
    
        bulk.ColumnMappings.Add(new SqlBulkCopyColumnMapping("amount", "amount"));
        bulk.ColumnMappings.Add(new SqlBulkCopyColumnMapping("date", "date"));
        bulk.BatchSize = 25;
        bulk.DestinationTableName = "statement";
        bulk.WriteToServer(GetTable());
    

正如 Amal 所述,由于 Identity 列,您需要列映射。

【讨论】:

不应该是“SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.KeepNulls”吗?【参考方案2】:

SQL 日期类型不同于 SQL 日期时间类型。我认为表中的日期列需要是 DateTime 类型,具体取决于您使用它的方式。

SQL Date Type SQL DateTime type

更新:

我认为 Marc 的答案应该有效,但您可能需要指定从源 DataTable 到目标的 SqlBulkCopyColumnMappings,否则可能会因为输入表的结构与输出表不完全匹配(即顺序)而导致映射错误日期和行列的交换数。

例如

var amount = new SqlBulkCopyColumnMapping("amount", "amount");
var date = new SqlBulkCopyColumnMapping("date", "date");
bulk.ColumnMappings.Add(amount);
bulk.ColumnMappings.Add(date);

【讨论】:

是的,我知道它们是不同的。但是,如果到处都是 DbType.DateTime / SqlDateTime / DateTime,我怎么能准确地使用 DbType.Date?! 您可以在用于批量加载的临时表中使用更广泛使用的“DATETIME”,然后在“真实”数据表中使用实际的“DATE”。您可以在 T-SQL 语句中轻松地将 DateTime 分配给 Date。【参考方案3】:

SqlDateTime 代表原来的datetime 类型。您是否尝试过在DataTable 中仅使用DateTime .NET 类型?我希望它可以将其转换为 TSQL datetimedate 类型。同上 decimal 而不是 SqlDecimal

【讨论】:

如果我使用 typeof(Double) 比会得到错误:“来自数据源的 SqlString 类型的给定值无法转换为指定目标列的十进制类型”。与 typeof(DateTime) 相同的错误!而且我不能使用 typeof(Decimal) 因为适当的列代表金钱并且需要 2 个十进制数字..

以上是关于使用 SqlBulkCopy 插入数据时出错的主要内容,如果未能解决你的问题,请参考以下文章

使用 SQLBulkCopy 插入/更新数据库

使用SqlBulkCopy进行批量插入数据操作遇到的问题

SqlBulkCopy批量插入数据时,不执行触发器和约束的解决方法

使用SqlBulkCopy批量插入多条数据进入表中

用SqlBulkCopy批量插入数据 遇到的错误

使用 SqlBulkCopy,如何将数据插入到非默认数据库架构中的表中?