从bcp客户端收到colid 6的无效列长度

lx0bsm1f  于 2022-10-22  发布在  其他
关注(0)|答案(8)|浏览(179)

我想从c#代码将csv文件数据批量上传到sqlserver2005,但遇到了以下错误-
从bcp客户端接收到colid 6的无效列长度。
大容量复制写入数据库服务器时

doinxwow

doinxwow1#

我知道这篇帖子很旧,但我遇到了同样的问题,最终找到了一个解决方案,以确定是哪一列导致了问题,并根据需要将其报告回来。我确定SqlException中返回的**colid**不是从零开始的,因此需要从中减去1才能获得值。之后,它将用作SqlBulkCopy示例的_sortedColumnMappings ArrayList的索引,而不是添加到SqlBulkCopy示例的列Map的索引。需要注意的一点是,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;
}
vybvopom

vybvopom2#

excel中的一个数据列(列Id 6)有一个或多个单元格数据超出了数据库中的数据列数据类型长度。
在excel中验证数据。还要验证excel中的数据格式是否符合数据库表模式。
为了避免这种情况,请尝试超过数据库表中字符串数据类型的数据长度。
希望这有帮助。

daupos2t

daupos2t3#

在使用SQLBulkCopy选项将字符串传递给数据库表时,我遇到了类似的问题。我传递的字符串是3个字符,而目标列长度是varchar(20)。我尝试在使用Trim()函数插入DB之前修剪字符串,以检查问题是否是由于字符串中的任何空格(前导和尾随)造成的。修剪完绳子后,它工作得很好。
你可以试试text.Trim()

ktca8awb

ktca8awb4#

检查正在执行大容量插入/复制的表中列的大小。varchar或其他字符串列可能需要扩展,或者插入的值需要修剪。列顺序也应与表中的相同。
e、 g,将varchar列30的大小增加到50=>
ALTER TABLE[dbo]。[TableName]ALTER COLUMN[ColumnName]Varchar(50)

dwthyt8l

dwthyt8l5#

很棒的代码,谢谢分享!
我最终使用反射来获取实际的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;
}
czq61nw1

czq61nw16#

我在一个更新的ssis版本中收到了这个错误消息(vs 2015企业版,我认为是ssis 2016)。我将在这里发表评论,因为这是在您搜索此错误消息时出现的第一个参考。我认为当源字符大小大于目标字符大小时,这种情况主要发生在字符列上。我在使用ado时收到了这条消息。net从teradata数据库输入到mssql。有趣的是,以前的oledb写入ms-sql完全处理了所有的字符转换,没有代码重写。colid编号和您有时从colid消息中获得的相应的Destination Input列#是毫无价值的。当你从Map的顶部开始倒数时,它不是列或者类似的东西。如果我是微软,我会很尴尬地给出一条错误消息,它看起来像是指向问题列,而事实并非如此。我通过做出有根据的猜测,然后将Map的输入更改为“忽略”,然后重新运行,查看消息是否消失,从而找到了问题所在。在我的案例和我的环境中,我通过substr修复了它('将Teradata输入设置为输出列的ms-sql声明的字符大小。检查并确保您的输入子字符串在所有数据转换和Map中传播。在我的情况下,它没有传播,我不得不删除所有的数据转换和映像,然后重新开始。OLEDB刚刚处理了它,ADO.net抛出了错误,不得不进行所有这些干预,这再次有趣让它发挥作用。通常,当目标为MS Sql时,应使用OLEDB。

dl5txlt9

dl5txlt97#

我只是偶然发现了这一点,使用@b_stil的代码片段,我找到了罪魁祸首列。在进一步的调查中,我认为我需要像@Liji Chandran建议的那样修改列,但我使用的是IExcelDataReader,我无法找到一个简单的方法来验证和修改我的160个列中的每一个。
然后我从CSVReader偶然发现了this class, (ValidatingDataReader)类。
这个类的有趣之处在于,它给出了源列和目标列的数据长度、错误行,甚至是导致错误的列值。
我所做的只是修剪所有(nvarchar、varchar和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;
    }

希望这能帮助某人

q1qsirdb

q1qsirdb8#

我一直在使用SqlBulkCopy将Access数据库传输到SQL。简单地说,我在SQL中创建每个表,将相应的Access表加载到DataTable中,然后SqlBulkCopy将DataTable复制到相应的SQL表中。因为我使用了一个标准化的函数来实现这一点,所以我没有设置任何ColumnMappings。当没有ColumnMappings时,SqlBulkCopy似乎只是将列0Map到列0,将列1Map到列1,以此类推。
在我的例子中,我必须确保Access表中的列顺序与新SQL表中的顺序完全匹配。一旦我做到了,它就按预期运行了。

相关问题