【发布时间】:2014-02-12 12:03:52
【问题描述】:
我正在尝试使用 BulkCopy.WriteToServer() 将 1000 万行从 Oracle 批量插入到 SQL Server。
我确定了
- 两边的表列和数据类型是一样的。我的意思是 Oracle 的 Date 数据类型映射到 Sql Server 的 datetime 数据类型。 Varchar2 映射到 varchar 等。
- 目标表上没有触发器和索引
当涉及到大约 140 万行时,它因 System.ArgumentOutOfRangeException 失败:Hour、Minute 和 Second 参数描述了无法表示的 DateTime。在 System.DateTime.DateToTicks(Int32 年,Int32 月,Int32 日)
这是我的代码
SqlBulkCopy copy;
copy = new SqlBulkCopy(destConn, SqlBulkCopyOptions.TableLock, null);
// ColumnMappings property is used to map column positions, not data type
copy.DestinationTableName = DestTable;
copy.NotifyAfter = 5000;
copy.SqlRowsCopied += new SqlRowsCopiedEventHandler(OnSqlRowsCopied);
copy.BulkCopyTimeout = 0;
try { copy.WriteToServer((IDataReader)rd); }
catch (Exception ex)
{
AppInfo.TableMsg[SrcTable] = AppInfo.TableMsg[SrcTable] + "\r\n" + "bulkcopy.WriteToServer(rd) failed. " + ex.Message;
throw ex;
}
我的表有 100 多列,有 26 个 DATE 列。坏数据在哪里很难分清
所以我这里有 3 个问题
- 是否有任何设置/选项可以使 WriteToServer() 继续或忽略异常?或者我可以在 catch 块中做些什么来让它继续?我不在乎留下不好的数据。我正在寻找一种方法来告诉它在插入错误时继续。
- 有什么方法可以防止这种情况发生吗?例如,我可以在填充 OracleDataReader 的选择查询中做什么?
- 如果以上2个问题都没有解决,那么有没有什么好的方法可以清除Oracle方面的“坏日期”?
谢谢,
更新: 我做了以下
- 将目标表数据类型从 datetime 更改为 datetime2
-
修改选择列表为
CASE WHEN my_date_column
对于所有具有 DATE 数据类型的列。
但错误仍然存在。这是完整的错误消息。
System.ArgumentOutOfRangeException was caught
HResult=-2146233086
Message=Hour, Minute, and Second parameters describe an un-representable DateTime.
Source=mscorlib
StackTrace:
at System.DateTime.TimeToTicks(Int32 hour, Int32 minute, Int32 second)
at Oracle.DataAccess.Client.OracleDataReader.GetDateTime(Int32 i)
at Oracle.DataAccess.Client.OracleDataReader.GetValue(Int32 i)
at System.Data.SqlClient.SqlBulkCopy.GetValueFromSourceRow(Int32 destRowIndex, Boolean& isSqlType, Boolean& isDataFeed, Boolean& isNull)
at System.Data.SqlClient.SqlBulkCopy.ReadWriteColumnValueAsync(Int32 col)
at System.Data.SqlClient.SqlBulkCopy.CopyColumnsAsync(Int32 col, TaskCompletionSource`1 source)
at System.Data.SqlClient.SqlBulkCopy.CopyRowsAsync(Int32 rowsSoFar, Int32 totalRows, CancellationToken cts, TaskCompletionSource`1 source)
at System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsyncContinued(BulkCopySimpleResultSet internalResults, String updateBulkCommandText, CancellationToken cts, TaskCompletionSource`1 source)
at System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsync(BulkCopySimpleResultSet internalResults, String updateBulkCommandText, CancellationToken cts, TaskCompletionSource`1 source)
at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalRestContinuedAsync(BulkCopySimpleResultSet internalResults, CancellationToken cts, TaskCompletionSource`1 source)
at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalRestAsync(CancellationToken cts, TaskCompletionSource`1 source)
at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalAsync(CancellationToken ctoken)
at System.Data.SqlClient.SqlBulkCopy.WriteRowSourceToServerAsync(Int32 columnCount, CancellationToken ctoken)
at System.Data.SqlClient.SqlBulkCopy.WriteToServer(IDataReader reader)
从错误消息看来,有问题的部分是 OracleDataReader 而不是 SqlBulkCopy。
如何使用 Oracle 查询快速发现这些违规值? 还有什么建议吗?
【问题讨论】:
标签: c# sql-server oracle etl