csvファイルデータをc#コードからSQL Server 2005に一括アップロードしたいのですが、以下のエラーが発生します-
colid6のbcpクライアントから無効な列長を受け取りました。
データベースサーバーへの一括コピー書き込み時
回答:
この投稿が古いことは知っていますが、同じ問題が発生し、最終的に問題の原因となっている列を特定し、必要に応じて報告するための解決策を見つけました。colid
SqlExceptionで返される値はゼロベースではないと判断したため、値を取得するには、そこから1を引く必要があります。その後_sortedColumnMappings
、SqlBulkCopyインスタンスに追加された列マッピングのインデックスではなく、SqlBulkCopyインスタンスのArrayListのインデックスとして使用されます。注意すべき点の1つは、SqlBulkCopyは最初に受信したエラーで停止するため、これが唯一の問題ではない可能性がありますが、少なくともそれを理解するのに役立ちます。
try
{
bulkCopy.WriteToServer(importTable);
sqlTran.Commit();
}
catch (SqlException ex)
{
if (ex.Message.Contains("Received an invalid column length from the bcp client for colid"))
{
string pattern = @"\d+";
Match match = Regex.Match(ex.Message.ToString(), pattern);
var index = Convert.ToInt32(match.Value) -1;
FieldInfo fi = typeof(SqlBulkCopy).GetField("_sortedColumnMappings", BindingFlags.NonPublic | BindingFlags.Instance);
var sortedColumns = fi.GetValue(bulkCopy);
var items = (Object[])sortedColumns.GetType().GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(sortedColumns);
FieldInfo itemdata = items[index].GetType().GetField("_metadata", BindingFlags.NonPublic | BindingFlags.Instance);
var metadata = itemdata.GetValue(items[index]);
var column = metadata.GetType().GetField("column", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).GetValue(metadata);
var length = metadata.GetType().GetField("length", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).GetValue(metadata);
throw new DataFormatException(String.Format("Column: {0} contains data with a length greater than: {1}", column, length));
}
throw;
}
SQL BulkCopyオプションを使用してデータベーステーブルに文字列を渡すときに、同様の問題に直面しました。渡した文字列は3文字でしたが、宛先列の長さはでしたvarchar(20)
。Trim()
関数を使用してDBに挿入する前に文字列をトリミングして、問題の原因が文字列のスペース(先頭と末尾)にあるかどうかを確認してみました。文字列をトリミングした後、それはうまくいきました。
あなたが試すことができます text.Trim()
一括挿入/コピーを実行しているテーブルの列のサイズを確認してください。varcharまたはその他の文字列列を拡張するか、挿入する値をトリミングする必要がある場合があります。列の順序も表と同じである必要があります。
例:varchar列のサイズを30から50に増やします=>
ALTER TABLE [dbo]。[TableName] ALTER COLUMN [ColumnName] Varchar(50)
素晴らしいコード、共有してくれてありがとう!
最終的にリフレクションを使用して、エラー時に実際のDataMemberNameをクライアントにスローバックしました(WCFサービスで一括保存を使用しています)。うまくいけば、他の誰かが私がそれをどのようにしたかが役に立つとわかるでしょう。
static string GetDataMemberName(string colName, object t) {
foreach(PropertyInfo propertyInfo in t.GetType().GetProperties()) {
if (propertyInfo.CanRead) {
if (propertyInfo.Name == colName) {
var attributes = propertyInfo.GetCustomAttributes(typeof(DataMemberAttribute), false).FirstOrDefault() as DataMemberAttribute;
if (attributes != null && !string.IsNullOrEmpty(attributes.Name))
return attributes.Name;
return colName;
}
}
}
return colName;
}
このエラーメッセージは、はるかに新しいssisバージョンで表示されます(2015エンタープライズと比較して、ssis 2016だと思います)。これは、このエラーメッセージをグーグルで検索したときに最初に表示される参照であるため、ここでコメントします。ソース文字サイズがターゲット文字サイズよりも大きい場合、ほとんどの場合、文字列で発生すると思います。このメッセージは、teradataデータベースからmssqlへのado.net入力を使用しているときに表示されました。以前のoledbがmssqlに書き込むと、コーディングのオーバーライドなしですべての文字変換が完全に処理されたため、おかしいです。コリッド番号と、コリッドメッセージで時々表示される対応する宛先入力列#は価値がありません。マッピングの上からカウントダウンするときの列ではありません。私がマイクロソフトだったら、dそうでないのに、問題の列を指しているように見えるエラーメッセージを表示するのは恥ずかしいことです。知識に基づいた推測を行い、マッピングへの入力を「無視」に変更してから再実行して、メッセージが消えたかどうかを確認することで、問題が解決したことを発見しました。私の場合と私の環境では、substr( 'Teradata入力を出力列のmssql宣言の文字サイズに変更することで修正しました。入力substrがすべてのデータ変換とマッピングに伝播することを確認してください。そうではなく、すべてのデータ変換とマッピングを削除して最初からやり直す必要がありました。OLEDBがそれを処理し、ADO.netがエラーをスローし、それを機能させるためにこのすべての介入が必要だったのはおかしいです。ターゲットがMSSqlの場合は、OLEDBを使用する必要があります。s問題のない列を指している。知識に基づいた推測を行い、マッピングへの入力を「無視」に変更してから再実行して、メッセージが消えたかどうかを確認することで、問題が解決したことを発見しました。私の場合と私の環境では、substr( 'Teradata入力を出力列のmssql宣言の文字サイズに変更することで修正しました。入力substrがすべてのデータ変換とマッピングに伝播することを確認してください。そうでない場合は、すべてのデータ変換とマッピングを削除して、最初からやり直す必要がありました。OLEDBがそれを処理し、ADO.netがエラーをスローし、それを機能させるためにこのすべての介入が必要だったのは、やはりおかしいです。ターゲットがMSSqlの場合は、OLEDBを使用する必要があります。s問題のない列を指している。知識に基づいた推測を行い、マッピングへの入力を「無視」に変更してから再実行して、メッセージが消えたかどうかを確認することで、問題が解決したことを発見しました。私の場合と私の環境では、substr( 'Teradata入力を出力列のmssql宣言の文字サイズに変更することで修正しました。入力substrがすべてのデータ変換とマッピングに伝播することを確認してください。そうでない場合は、すべてのデータ変換とマッピングを削除して、最初からやり直す必要がありました。OLEDBがそれを処理し、ADO.netがエラーをスローし、それを機能させるためにこのすべての介入が必要だったのは、やはりおかしいです。ターゲットがMSSqlの場合は、OLEDBを使用する必要があります。知識に基づいた推測を行い、マッピングへの入力を「無視」に変更してから再実行して、メッセージが消えたかどうかを確認することで、問題が解決したことを発見しました。私の場合と私の環境では、substr( 'Teradata入力を出力列のmssql宣言の文字サイズに変更することで修正しました。入力substrがすべてのデータ変換とマッピングに伝播することを確認してください。そうでない場合は、すべてのデータ変換とマッピングを削除して、最初からやり直す必要がありました。OLEDBがそれを処理し、ADO.netがエラーをスローし、それを機能させるためにこのすべての介入が必要だったのは、やはりおかしいです。ターゲットがMSSqlの場合は、OLEDBを使用する必要があります。知識に基づいた推測を行い、マッピングへの入力を「無視」に変更してから再実行して、メッセージが消えたかどうかを確認することで、問題が解決したことを発見しました。私の場合と私の環境では、substr( 'Teradata入力を出力列のmssql宣言の文字サイズに変更することで修正しました。入力substrがすべてのデータ変換とマッピングに伝播することを確認してください。そうではなく、すべてのデータ変換とマッピングを削除して最初からやり直す必要がありました。OLEDBがそれを処理し、ADO.netがエラーをスローし、それを機能させるためにこのすべての介入が必要だったのはおかしいです。ターゲットがMSSqlの場合は、OLEDBを使用する必要があります。とマッピングを実行し、最初からやり直します。OLEDBがそれを処理し、ADO.netがエラーをスローし、それを機能させるためにこのすべての介入が必要だったこともおかしいです。一般に、ターゲットがMS Sqlの場合は、OLEDBを使用する必要があります。sとマッピングを実行し、最初からやり直します。OLEDBがそれを処理し、ADO.netがエラーをスローし、それを機能させるためにこのすべての介入が必要だったこともおかしいです。一般に、ターゲットがMS Sqlの場合は、OLEDBを使用する必要があります。
私はこれに偶然出くわし、@ b_stilのスニペットを使用して、原因の列を特定することができました。さらに調査したところ、@ Liji Chandranが提案したように列をトリミングする必要があると思いましたが、IExcelDataReaderを使用していたため、160列のそれぞれを検証してトリミングする簡単な方法がわかりませんでした。
次に、CSVReaderのこのクラス(ValidatingDataReader)クラスに出くわしました。
このクラスの興味深い点は、ソース列と宛先列のデータ長、原因の行、さらにはエラーの原因となっている列の値を提供することです。
私がしたのは、すべての(nvarchar、varchar、char、およびnchar)列をトリミングすることだけでした。
GetValue
メソッドを次のように変更しました。
object IDataRecord.GetValue(int i)
{
object columnValue = reader.GetValue(i);
if (i > -1 && i < lookup.Length)
{
DataRow columnDef = lookup[i];
if
(
(
(string)columnDef["DataTypeName"] == "varchar" ||
(string)columnDef["DataTypeName"] == "nvarchar" ||
(string)columnDef["DataTypeName"] == "char" ||
(string)columnDef["DataTypeName"] == "nchar"
) &&
(
columnValue != null &&
columnValue != DBNull.Value
)
)
{
string stringValue = columnValue.ToString().Trim();
columnValue = stringValue;
if (stringValue.Length > (int)columnDef["ColumnSize"])
{
string message =
"Column value \"" + stringValue.Replace("\"", "\\\"") + "\"" +
" with length " + stringValue.Length.ToString("###,##0") +
" from source column " + (this as IDataRecord).GetName(i) +
" in record " + currentRecord.ToString("###,##0") +
" does not fit in destination column " + columnDef["ColumnName"] +
" with length " + ((int)columnDef["ColumnSize"]).ToString("###,##0") +
" in table " + tableName +
" in database " + databaseName +
" on server " + serverName + ".";
if (ColumnException == null)
{
throw new Exception(message);
}
else
{
ColumnExceptionEventArgs args = new ColumnExceptionEventArgs();
args.DataTypeName = (string)columnDef["DataTypeName"];
args.DataType = Type.GetType((string)columnDef["DataType"]);
args.Value = columnValue;
args.SourceIndex = i;
args.SourceColumn = reader.GetName(i);
args.DestIndex = (int)columnDef["ColumnOrdinal"];
args.DestColumn = (string)columnDef["ColumnName"];
args.ColumnSize = (int)columnDef["ColumnSize"];
args.RecordIndex = currentRecord;
args.TableName = tableName;
args.DatabaseName = databaseName;
args.ServerName = serverName;
args.Message = message;
ColumnException(args);
columnValue = args.Value;
}
}
}
}
return columnValue;
}
これが誰かを助けることを願っています