95

我想从 c# 代码批量上传 csv 文件数据到 sql server 2005,但我遇到以下错误 -

从 bcp 客户端接收到针对 colid 6 的无效列长度。

当批量复制写入数据库服务器时

4

7 回答 7

214

我知道这篇文章很旧,但我遇到了同样的问题,最后找到了一个解决方案来确定是哪一列导致了问题并根据需要报告回来。我确定colid在 SqlException 中返回的不是基于零的,因此您需要从中减去 1 才能获得该值。之后,它用作 SqlBulkCopy 实例的_sortedColumnMappingsArrayList 的索引,而不是添加到 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;
}
于 2013-10-31T17:02:42.623 回答
72

excel 中的数据列之一(列 ID 6)有一个或多个单元格数据超过数据库中的 datacolumn 数据类型长度。

验证excel中的数据。还要验证 excel 中的数据的格式是否符合数据库表模式。

为避免这种情况,请尝试超过数据库表中字符串数据类型的数据长度。

希望这可以帮助。

于 2012-05-04T05:15:11.503 回答
4

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

你可以试试text.Trim()

于 2015-07-16T07:17:11.810 回答
1

检查您正在执行批量插入/复制的表中列的大小。varchar 或其他字符串列可能需要扩展,或者您插入的值需要修剪。列顺序也应与表中相同。

例如,将 varchar 列的大小从 30 增加到 50 =>

ALTER TABLE [dbo].[TableName] ALTER COLUMN [ColumnName] Varchar(50)

于 2017-08-25T01:42:34.740 回答
0

很不错的一段代码,谢谢分享!

我最终使用反射来获取实际的 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;
}

于 2016-02-01T20:51:23.080 回答
0

我收到了这个错误消息,它有一个更新的 ssis 版本(与 2015 企业版相比,我认为它是 ssis 2016)。我将在这里发表评论,因为这是您在谷歌上搜索此错误消息时出现的第一个参考。我认为当源字符大小大于目标字符大小时,它主要发生在字符列中。当我使用 ado.net 从 teradata 数据库输入 ms sql 时收到此消息。有趣的是,先前的 oledb 写入 ms sql 完美地处理了所有字符转换,没有编码覆盖。colid 编号和相应的 Destination Input 列 # 您有时会从 colid 消息中获得毫无价值。当您从映射顶部倒数或类似的东西时,它不是列。如果我是微软,我 d 很尴尬地给出一个错误消息,看起来它指向问题列,而实际上它不是。我通过有根据的猜测发现了问题,然后将映射的输入更改为“忽略”,然后重新运行并查看消息是否消失。在我的情况和我的环境中,我通过 substr( 将 Teradata 输入修复为输出列的 ms sql 声明的字符大小。检查并确保您的输入 substr 通过所有数据转换和映射传播。在我的如果没有,我不得不删除所有数据转换和映射并重新开始。再次有趣的是,OLEDB 刚刚处理了它,ADO.net 抛出了错误,必须进行所有这些干预才能使其正常工作。一般来说,你当您的目标是 MS Sql 时应该使用 OLEDB。s 指向问题列,而不是。我通过有根据的猜测发现了问题,然后将映射的输入更改为“忽略”,然后重新运行并查看消息是否消失。在我的情况和我的环境中,我通过 substr( 将 Teradata 输入修复为输出列的 ms sql 声明的字符大小。检查并确保您的输入 substr 通过所有数据转换和映射传播。在我的如果没有,我不得不删除所有数据转换和映射并重新开始。再次有趣的是,OLEDB 刚刚处理了它,ADO.net 抛出了错误,必须进行所有这些干预才能使其正常工作。一般来说,你当您的目标是 MS Sql 时应该使用 OLEDB。s 指向问题列,而不是。我通过有根据的猜测发现了问题,然后将映射的输入更改为“忽略”,然后重新运行并查看消息是否消失。在我的情况和我的环境中,我通过 substr( 将 Teradata 输入修复为输出列的 ms sql 声明的字符大小。检查并确保您的输入 substr 通过所有数据转换和映射传播。在我的如果没有,我不得不删除所有数据转换和映射并重新开始。再次有趣的是,OLEDB 刚刚处理了它,ADO.net 抛出了错误,必须进行所有这些干预才能使其正常工作。一般来说,你当您的目标是 MS Sql 时应该使用 OLEDB。我通过有根据的猜测发现了问题,然后将映射的输入更改为“忽略”,然后重新运行并查看消息是否消失。在我的情况和我的环境中,我通过 substr( 将 Teradata 输入修复为输出列的 ms sql 声明的字符大小。检查并确保您的输入 substr 通过所有数据转换和映射传播。在我的如果没有,我不得不删除所有数据转换和映射并重新开始。再次有趣的是,OLEDB 刚刚处理了它,ADO.net 抛出了错误,必须进行所有这些干预才能使其正常工作。一般来说,你当您的目标是 MS Sql 时应该使用 OLEDB。我通过有根据的猜测发现了问题,然后将映射的输入更改为“忽略”,然后重新运行并查看消息是否消失。在我的情况和我的环境中,我通过 substr( 将 Teradata 输入修复为输出列的 ms sql 声明的字符大小。检查并确保您的输入 substr 通过所有数据转换和映射传播。在我的如果没有,我不得不删除所有数据转换和映射并重新开始。再次有趣的是,OLEDB 刚刚处理了它,ADO.net 抛出了错误,必须进行所有这些干预才能使其正常工作。一般来说,你当您的目标是 MS Sql 时应该使用 OLEDB。s 和映射并重新开始。再次有趣的是,OLEDB 刚刚处理了它,而 ADO.net 抛出了错误,并且必须进行所有这些干预才能使其正常工作。一般来说,当您的目标是 MS Sql 时,您应该使用 OLEDB。s 和映射并重新开始。再次有趣的是,OLEDB 刚刚处理了它,而 ADO.net 抛出了错误,并且必须进行所有这些干预才能使其正常工作。一般来说,当您的目标是 MS Sql 时,您应该使用 OLEDB。

于 2019-10-23T22:24:39.607 回答
0

我只是偶然发现了这一点,并使用@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;
    }

希望这可以帮助某人

于 2020-01-04T16:42:55.710 回答