c # 코드에서 csv 파일 데이터를 SQL Server 2005로 대량 업로드하고 싶지만 아래 오류가 발생합니다.
colid 6에 대해 bcp 클라이언트에서 유효하지 않은 열 길이를 받았습니다.
대량 복사가 데이터베이스 서버에 쓸 때
답변:
Excel의 데이터 열 중 하나 (Column Id 6)에 데이터베이스의 datacolumn 데이터 유형 길이를 초과하는 하나 이상의 셀 데이터가 있습니다.
Excel에서 데이터를 확인하십시오. 또한 Excel의 데이터 형식이 데이터베이스 테이블 스키마를 준수하는지 확인하십시오.
이를 방지하려면 데이터베이스 테이블에서 문자열 데이터 유형의 데이터 길이를 초과하십시오.
도움이 되었기를 바랍니다.
이 게시물이 오래되었다는 것을 알고 있지만 동일한 문제가 발생하여 마침내 문제를 일으키는 열을 확인하고 필요에 따라보고하는 솔루션을 찾았습니다. 그 결정 colid
은 값을 얻기 위해 그것에서 1을 뺄 필요가 있도록 SQLEXCEPTION 반환 기반으로 0이 아닌. 그 후에 _sortedColumnMappings
는 SqlBulkCopy 인스턴스에 추가 된 열 매핑의 인덱스가 아닌 SqlBulkCopy 인스턴스 의 ArrayList 인덱스로 사용됩니다 . 한 가지 주목할 점은 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 버전에서이 오류 메시지를 받았습니다 (vs 2015 enterprise, ssis 2016 인 것 같습니다). 이 오류 메시지를 Google에 올릴 때 나타나는 첫 번째 참조이기 때문에 여기에 주석을 달겠습니다. 소스 문자 크기가 대상 문자 크기보다 클 때 주로 문자 열에서 발생한다고 생각합니다. teradata 데이터베이스에서 ms sql에 ado.net 입력을 사용할 때이 메시지를 받았습니다. 이전 oledb가 ms sql에 기록했기 때문에 코딩 재정의없이 모든 문자 변환을 완벽하게 처리했기 때문에 재미 있습니다. colid 메시지와 함께 때때로 얻는 colid 번호 및 해당 대상 입력 열 #은 쓸모가 없습니다. 매핑의 맨 위에서 카운트 다운하거나 이와 유사한 것은 열이 아닙니다. 내가 마이크로 소프트라면 그렇지 않은 경우 문제 열을 가리키는 것처럼 보이는 오류 메시지를 제공하는 것이 부끄럽습니다. 정보를 바탕으로 추측 한 다음 입력을 "무시"로 매핑으로 변경 한 다음 다시 실행하여 메시지가 사라 졌는지 확인하여 문제 colid를 찾았습니다. 내 경우와 내 환경에서는 출력 열에 대한 ms sql 선언의 문자 크기에 Teradata 입력을 substr ( 'ing으로 수정했습니다. 입력 substr이 모든 데이터 변환 및 매핑을 통해 전파되는지 확인하고 확인하십시오. 그렇지 않은 경우 모든 데이터 변환 및 매핑을 삭제하고 다시 시작해야했습니다. OLEDB가 방금 처리했고 ADO.net에서 오류를 발생 시켰고 작동하도록이 모든 개입이 필요했다는 사실이 재밌습니다. 일반적으로 당신은 대상이 MS SQL 일 때 OLEDB를 사용해야합니다. 그렇지 않은 경우 문제 열을 가리 킵니다. 정보를 바탕으로 추측 한 다음 매핑에 대한 입력을 "무시"로 변경 한 다음 다시 실행하여 메시지가 사라 졌는지 확인하여 문제 colid를 찾았습니다. 내 경우와 내 환경에서는 출력 열에 대한 ms sql 선언의 문자 크기에 Teradata 입력을 substr ( 'ing으로 수정했습니다. 입력 substr이 모든 데이터 변환 및 매핑을 통해 전파되는지 확인하고 확인하십시오. 그렇지 않은 경우 모든 데이터 변환 및 매핑을 삭제하고 다시 시작해야했습니다. OLEDB가 방금 처리했고 ADO.net에서 오류를 발생 시켰고 작동하도록이 모든 개입이 필요했다는 사실이 재밌습니다. 일반적으로 당신은 대상이 MS SQL 일 때 OLEDB를 사용해야합니다. 그렇지 않은 경우 문제 열을 가리 킵니다. 정보를 바탕으로 추측 한 다음 매핑에 대한 입력을 "무시"로 변경 한 다음 다시 실행하여 메시지가 사라 졌는지 확인하여 문제 colid를 찾았습니다. 내 경우와 내 환경에서는 출력 열에 대한 ms sql 선언의 문자 크기에 Teradata 입력을 substr ( 'ing으로 수정했습니다. 입력 substr이 모든 데이터 변환 및 매핑을 통해 전파되는지 확인하고 확인하십시오. 그렇지 않은 경우 모든 데이터 변환 및 매핑을 삭제하고 다시 시작해야했습니다. OLEDB가 방금 처리했고 ADO.net에서 오류를 발생 시켰고 작동하도록이 모든 개입이 필요했다는 사실이 재밌습니다. 일반적으로 당신은 대상이 MS SQL 일 때 OLEDB를 사용해야합니다. 정보를 바탕으로 추측 한 다음 매핑에 대한 입력을 "무시"로 변경 한 다음 다시 실행하여 메시지가 사라 졌는지 확인하여 문제 colid를 찾았습니다. 내 경우와 내 환경에서는 출력 열에 대한 ms sql 선언의 문자 크기에 Teradata 입력을 substr ( 'ing으로 수정했습니다. 입력 substr이 모든 데이터 변환 및 매핑을 통해 전파되는지 확인하고 확인하십시오. 그렇지 않은 경우 모든 데이터 변환 및 매핑을 삭제하고 다시 시작해야했습니다. OLEDB가 방금 처리했고 ADO.net에서 오류를 발생 시켰고 작동하도록이 모든 개입이 필요했다는 사실이 재밌습니다. 일반적으로 당신은 대상이 MS SQL 일 때 OLEDB를 사용해야합니다. 정보를 바탕으로 추측 한 다음 매핑에 대한 입력을 "무시"로 변경 한 다음 다시 실행하여 메시지가 사라 졌는지 확인하여 문제 colid를 찾았습니다. 내 경우와 내 환경에서는 출력 열에 대한 ms sql 선언의 문자 크기에 Teradata 입력을 substr ( 'ing으로 수정했습니다. 입력 substr이 모든 데이터 변환 및 매핑을 통해 전파되는지 확인하고 확인하십시오. 그렇지 않은 경우 모든 데이터 변환 및 매핑을 삭제하고 다시 시작해야했습니다. OLEDB가 방금 처리했고 ADO.net에서 오류를 발생 시켰고 작동하도록이 모든 개입이 필요했다는 사실이 재밌습니다. 일반적으로 당신은 대상이 MS SQL 일 때 OLEDB를 사용해야합니다. s 및 매핑 및 다시 시작하십시오. 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;
}
이것이 누군가에게 도움이되기를 바랍니다.