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

时间:2012-05-04 04:22:54

标签: c# .net sql-server database sql-server-2005

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

  

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

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

7 个答案:

答案 0 :(得分:149)

我知道这篇文章已经过时了,但我遇到了同样的问题,最终找到了一个解决方案来确定导致问题的列并根据需要报告。我确定在SqlException中返回的 colid 不是基于零的,因此您需要从中减去1以获取该值。之后,它被用作SqlBulkCopy实例的_sortedColumnMappings 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;
}

答案 1 :(得分:55)

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

验证excel中的数据。还要验证excel中的数据,使其格式符合数据库表模式。

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

希望这有帮助。

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:0)

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

您可以尝试text.Trim()

答案 4 :(得分: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;
}




答案 5 :(得分:0)

我收到了一个错误的错误消息,并带有更新的sis版本(vs 2015企业版,我认为是sis 2016)。我将在这里发表评论,因为这是您在搜索此错误消息时出现的第一个参考。我认为当源字符大小大于目标字符大小时,大多数情况下字符列都会发生这种情况。我从Teradata数据库使用ado.net输入到ms sql时收到了此消息。很有趣,因为先前的oledb写入ms sql可以完美地处理所有字符转换,而没有任何编码覆盖。大肠菌群编号和您有时通过大肠菌群消息获得的相应“目标输入”列号是毫无价值的。从映射顶部或类似位置向下计数时,它不是该列。如果我是microsoft,我会很尴尬地给出一条错误消息,看起来好像是指向问题列的,而不是指向问题列。通过进行有根据的猜测,然后将输入的映射更改为“忽略”,然后重新运行以查看消息是否消失,我发现了大肠杆菌病。就我而言,在我的环境中,我通过将Teradata输入替换为输出列的ms sql声明的字符大小来修复它。检查并确保您的输入substr在所有数据转换和映射中传播。如果没有,我必须删除所有的“数据转换”和“映射”,然后重新开始。再次有趣的是,OLEDB刚刚处理了它,而ADO.net抛出了错误,必须进行所有这些干预才能使其正常工作。您的目标是MS Sql时应使用OLEDB。

答案 6 :(得分:0)

我偶然发现了这个问题,并使用@b_stil的代码片段,弄清了罪魁祸首列。在进一步的调查中,我认为我需要像@Liji Chandran所建议的那样对列进行修整,但是我使用的是IExcelDataReader,我想不出一种简单的方法来验证和修整我的160列。

然后我偶然发现了this class, (ValidatingDataReader)CSVReader类。

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

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

我刚刚将 $scope.renderCharts = function(){ $scope.riskChart = new dc.pieChart('#risk-chart'); $scope.ndx = crossfilter([{dd: new Date(), volume: 35}, {dd: new Date(), volume: 6}, {dd: new Date(), volume: 8}]); $scope.quarter = $scope.ndx.dimension(d => { const month = d.dd.getMonth(); if (month <= 2) { return 'Q1'; } else if (month > 2 && month <= 5) { return 'Q2'; } else if (month > 5 && month <= 8) { return 'Q3'; } else { return 'Q4'; } }); $scope.quarterGroup = $scope.quarter.group().reduceSum(d => d.volume); $timeout(()=>{ var riskchart = document.getElementById('risk-chart'); height = Math.floor(riskchart.offsetHeight) - 2*parseInt(window.getComputedStyle(riskchart, null).getPropertyValue('padding-top')); width = Math.floor(parseFloat(window.getComputedStyle(riskchart, null).width)) - 2*parseInt(window.getComputedStyle(riskchart, null).getPropertyValue('padding-top')); var padding = parseInt(window.getComputedStyle(riskchart, null).getPropertyValue('padding-top')); $scope.riskChart /* dc.pieChart('#quarter-chart', 'chartGroup') */ .width(width) .height(height) .radius(Math.round(height/2.0)) .innerRadius(Math.round(height/4.0)) .dimension($scope.quarter) .group($scope.quarterGroup) .transitionDuration(500); apply_resizing($scope.riskChart, width, height, null, 'risk-chart'); anchor = $scope.riskChart.anchor(); $scope.riskChart.render(); var left = (riskchart.getBoundingClientRect().width-padding)/2.0 -(width)/2.0 - padding; var top = document.querySelector("div[ng-app='Risk']").getBoundingClientRect().top + riskchart.getBoundingClientRect().top + 2*padding; if (document.querySelectorAll(anchor + " svg").length > 0) (document.querySelectorAll(anchor + " svg g:first-of-type")[0]).setAttribute("transform", "translate(" + Math.floor(left) + ", " + Math.floor(top) + ")") var gridElement = angular.element(document.getElementById('risk-chart')); gridElement.on('gridster-resized', ()=>{alert(); resize($scope.riskchart, width, height, true, 'risk-chart')}); }); } 方法更改为此:

GetValue

希望这对某人有帮助