source

collid 6에 대해 bcp 클라이언트로부터 잘못된 열 길이를 수신했습니다.

factcode 2023. 5. 14. 11:09
반응형

collid 6에 대해 bcp 클라이언트로부터 잘못된 열 길이를 수신했습니다.

csv 파일 데이터를 c# 코드에서 sql server 2005로 대량 업로드하려고 하는데 아래 오류가 발생했습니다.

collid 6에 대해 bcp 클라이언트로부터 잘못된 열 길이를 받았습니다.

데이터베이스 서버에 대량 복사 쓰기 시

이 게시물이 오래된 것으로 알고 있지만 동일한 문제에 부딪혀 문제의 원인이 되는 열을 확인하고 필요에 따라 다시 보고할 수 있는 해결책을 찾았습니다.SqlException에 반환된 값이 0을 기반으로 하지 않으므로 값을 얻으려면 1을 빼야 합니다.그 후에 그것은 지수로 사용됩니다._sortedColumnMappingsSqlBulkCopy 인스턴스의 ArrayList는 SqlBulkCopy 인스턴스에 추가된 열 매핑의 인덱스가 아닙니다.한 가지 주의할 점은 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;
}

Excel의 데이터 열 중 하나(열 ID 6)에 데이터베이스의 데이터 열 데이터 유형 길이를 초과하는 셀 데이터가 하나 이상 있습니다.

엑셀의 데이터를 확인합니다.또한 Excel의 데이터 형식이 데이터베이스 테이블 스키마를 준수하는지 확인합니다.

이 문제를 방지하려면 데이터베이스 테이블에서 문자열 데이터 유형의 데이터 길이를 초과하십시오.

이게 도움이 되길 바랍니다.

SQL BulkCopy 옵션을 사용하여 데이터베이스 테이블에 문자열을 전달하는 동안 비슷한 문제가 발생했습니다.전달하는 문자열은 3자인 반면 대상 열 길이는varchar(20)다음을 사용하여 DB에 삽입하기 전에 문자열을 트리밍해 보았습니다.Trim()문제가 문자열의 공백(선행 및 후행) 때문인지 확인하는 함수입니다.끈을 다듬은 후에, 잘 작동했습니다.

시도해 보세요text.Trim()

대량 삽입/복사 중인 테이블의 열 크기를 확인합니다.막대 또는 다른 문자열 열을 확장하거나 삽입할 값을 잘라내야 할 수 있습니다.열 순서도 표와 같아야 합니다.

예, varchar column 30에서 50으로 크기 증가 =>

대체 테이블 [dbo].[표명] ALTER COLUMN [칼럼명] Varchar (50)

SQLBulkCopy를 사용하여 액세스 데이터베이스를 SQL로 전송하고 있습니다.즉, SQL에서 각 테이블을 생성하고 해당 액세스 테이블을 데이터 테이블에 로드한 다음 SqlBulk 데이터 테이블을 해당 SQL 테이블에 복사합니다.표준화된 기능을 사용하여 ColumnMappings를 설정하지 않았습니다.ColumnMappings가 없는 경우 SqlBulkCopy는 컬럼 0을 컬럼 0에 매핑하고 컬럼 1을 컬럼 1에 매핑하는 것으로 보입니다.

제 경우 액세스 테이블의 열 순서가 새 SQL 테이블의 열 순서와 정확히 일치하는지 확인해야 했습니다.제가 그렇게 하자 예상대로 작동했습니다.

훌륭한 코드 조각입니다. 공유해 주셔서 감사합니다!

오류가 발생하면 실제 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 엔터프라이즈, ssis 2016인 것 같습니다)와 함께 이 오류 메시지를 받았습니다.이 오류 메시지를 검색할 때 가장 먼저 표시되는 참조이므로 여기에 설명하겠습니다.소스 문자 크기가 대상 문자 크기보다 클 때 주로 문자 열에서 발생하는 것 같습니다.teradata 데이터베이스에서 ado.net 입력 tms sql을 사용할 때 이 메시지가 표시되었습니다.이전 oledb 쓰기 tms sql이 코딩 재지정 없이 모든 문자 변환을 완벽하게 처리했기 때문에 재미있습니다.콜리드 번호와 콜리드 메시지와 함께 표시되는 해당 대상 입력 열 #은 값어치가 없습니다.매핑의 맨 위에서 카운트다운을 할 때 열이 아닙니다.제가 Microsoft라면 문제 열을 가리키는 것처럼 보이지 않는 오류 메시지를 표시하는 것이 창피할 것입니다.저는 지식을 바탕으로 추측한 다음 매핑에 대한 입력을 "무시"로 변경한 다음 다시 실행하여 메시지가 사라졌는지 확인함으로써 문제가 딱딱하다는 것을 발견했습니다.나의 경우와 내 환경에서 나는 그것을 서브스트러('ing Teradata 입력을 출력 열에 대한 msql 선언의 문자 크기로 수정했습니다.모든 데이터 변환 및 매핑을 통해 입력 하위 시스템이 전파되는지 확인합니다.제 경우에는 그렇지 않았기 때문에 모든 데이터 변환 및 매핑을 삭제하고 다시 시작해야 했습니다.OLEDB가 방금 그것을 처리했고 ADO.net 가 오류를 던졌고 그것이 작동하도록 하기 위해 이 모든 개입이 있어야 했다는 것은 다시 한번 웃깁니다.일반적으로 대상이 MS SQL일 때는 OLEDB를 사용해야 합니다.

저는 이것을 우연히 발견했고 @b_still의 스니펫을 사용하여 범인 칼럼을 알아낼 수 있었습니다.이후의 조사에서, 저는 @Liji Chandran이 제안한 대로 칼럼을 다듬어야 한다고 생각했지만, IExcel DataReader를 사용하고 있었고 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;
    }

이것이 누군가에게 도움이 되기를 바랍니다.

언급URL : https://stackoverflow.com/questions/10442686/received-an-invalid-column-length-from-the-bcp-client-for-colid-6

반응형