C# 从 bcp 客户端收到一个无效的列长度,用于 colid 6

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10442686/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 13:53:51  来源:igfitidea点击:

Received an invalid column length from the bcp client for colid 6

c#.netsql-serverdatabasesql-server-2005

提问by Sana Sana

I want to bulk upload csv file data to sql server 2005 from c# code but I am encountering the below error -

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

Received an invalid column length from the bcp client for colid 6.

从 bcp 客户端收到一个无效的列长度,用于 colid 6。

when bulk copy write to database server

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

采纳答案by Dinesh

One of the data columns in the excel (Column Id 6) has one or more cell data that exceed the datacolumn datatype length in the database.

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

Verify the data in excel. Also verify the data in the excel for its format to be in compliance with the database table schema.

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

To avoid this, try exceeding the data-length of the string datatype in the database table.

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

Hope this helps.

希望这可以帮助。

回答by b_stil

I know this post is old but I ran into this same issue and finally figured out a solution to determine which column was causing the problem and report it back as needed. I determined that colidreturned in the SqlException is not zero based so you need to subtract 1 from it to get the value. After that it is used as the index of the _sortedColumnMappingsArrayList of the SqlBulkCopy instance not the index of the column mappings that were added to the SqlBulkCopy instance. One thing to note is that SqlBulkCopy will stop on the first error received so this may not be the only issue but at least helps to figure it out.

我知道这篇文章很旧,但我遇到了同样的问题,最后找到了一个解决方案来确定哪个列导致了问题并根据需要报告。我确定colidSqlException中返回的不是基于零的,因此您需要从中减去 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;
}

回答by Liji Chandran

I faced a similar kind of issue while passing a string to Database table using SQL BulkCopy option. The string i was passing was of 3 characters whereas the destination column length was varchar(20). I tried trimming the string before inserting into DB using Trim()function to check if the issue was due to any space (leading and trailing) in the string. After trimming the string, it worked fine.

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

You can try text.Trim()

你可以试试 text.Trim()

回答by infocyde

Great piece of code, thanks for sharing!

很棒的一段代码,谢谢分享!

I ended up using reflection to get the actual DataMemberName to throw back to a client on an error (I'm using bulk save in a WCF service). Hopefully someone else will find how I did it useful.

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

回答by Nalan Madheswaran

Check the size of the columns in the table you are doing bulk insert/copy. the varchar or other string columns might needs to be extended or the value your are inserting needs to be trim. Column order also should be same as in table.

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

e.g, Increase size of varchar column 30 to 50 =>

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

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

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

回答by renaissanceMan

I got this error message with a much more recent ssis version (vs 2015 enterprise, i think it's ssis 2016). I will comment here because this is the first reference that comes up when you google this error message. I think it happens mostly with character columns when the source character size is larger than the target character size. I got this message when I was using an ado.net input to ms sql from a teradata database. Funny because the prior oledb writes to ms sql handled all the character conversion perfectly with no coding overrides. The colid number and the a corresponding Destination Input column # you sometimes get with the colid message are worthless. It's not the column when you count down from the top of the mapping or anything like that. If I were microsoft, I'd be embarrased to give an error message that looks like it's pointing at the problem column when it isn't. I found the problem colid by making an educated guess and then changing the input to the mapping to "Ignore" and then rerun and see if the message went away. In my case and in my environment I fixed it by substr( 'ing the Teradata input to the character size of the ms sql declaration for the output column. Check and make sure your input substr propagates through all you data conversions and mappings. In my case it didn't and I had to delete all my Data Conversion's and Mappings and start over again. Again funny that OLEDB just handled it and ADO.net threw the error and had to have all this intervention to make it work. In general you should use OLEDB when your target is MS Sql.

我使用更新的 ssis 版本收到此错误消息(与 2015 企业版相比,我认为是 ssis 2016)。我将在这里发表评论,因为这是您在 google 上搜索此错误消息时出现的第一个参考。我认为当源字符大小大于目标字符大小时,它主要发生在字符列上。当我从 teradata 数据库使用 ado.net 输入到 ms sql 时,我收到了这条消息。有趣的是,之前的 oledb 写入 ms sql 完美地处理了所有字符转换,没有编码覆盖。您有时通过 colid 消息获得的 colid 编号和相应的 Destination Input 列 # 毫无价值。当您从映射顶部倒计时或类似的东西时,它不是列。如果我是微软,我' d 会尴尬地给出一条错误消息,看起来它指向问题列,但实际上并非如此。我通过有根据的猜测发现了问题,然后将映射的输入更改为“忽略”,然后重新运行并查看消息是否消失。在我的情况和我的环境中,我通过 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。我通过有根据的猜测发现了问题,然后将映射的输入更改为“忽略”,然后重新运行并查看消息是否消失。在我的情况和我的环境中,我通过 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。

回答by Ahmad Tijani

I just stumbled upon this and using @b_stil's snippet, I was able to figure the culprit column. And on futher investigation, I figured i needed to trim the column just like @Liji Chandran suggested but I was using IExcelDataReader and I couldn't figure out an easy way to validate and trim each of my 160 columns.

我只是偶然发现了这一点,并使用@b_stil 的片段,我能够找出罪魁祸首。在进一步调查中,我认为我需要像@Liji Chandran 建议的那样修剪该列,但我使用的是 IExcelDataReader,我无法找到一种简单的方法来验证和修剪我的 160 列中的每一列。

Then I stumbled upon this class, (ValidatingDataReader)class from CSVReader.

然后我偶然发现了这个类,来自CSVReader 的(ValidatingDataReader)类。

Interesting thing about this class is that it gives you the source and destination columns data length, the culprit row and even the column value that's causing the error.

这个类的有趣之处在于它为您提供了源列和目标列的数据长度、罪魁祸首行,甚至是导致错误的列值。

All I did was just trim all (nvarchar, varchar, char and nchar) columns.

我所做的只是修剪所有(nvarchar、varchar、char 和 nchar)列。

I just changed my GetValuemethod to this:

我只是将我的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;
    }

Hope this helps someone

希望这有助于某人