我想从c#代码将csv文件数据批量上传到sqlserver2005,但遇到了以下错误-从bcp客户端接收到colid 6的无效列长度。大容量复制写入数据库服务器时
doinxwow1#
我知道这篇帖子很旧,但我遇到了同样的问题,最终找到了一个解决方案,以确定是哪一列导致了问题,并根据需要将其报告回来。我确定SqlException中返回的**colid**不是从零开始的,因此需要从中减去1才能获得值。之后,它将用作SqlBulkCopy示例的_sortedColumnMappings ArrayList的索引,而不是添加到SqlBulkCopy示例的列Map的索引。需要注意的一点是,SqlBulkCopy将在收到第一个错误时停止,因此这可能不是唯一的问题,但至少有助于解决问题。
colid
_sortedColumnMappings
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; }
vybvopom2#
excel中的一个数据列(列Id 6)有一个或多个单元格数据超出了数据库中的数据列数据类型长度。在excel中验证数据。还要验证excel中的数据格式是否符合数据库表模式。为了避免这种情况,请尝试超过数据库表中字符串数据类型的数据长度。希望这有帮助。
daupos2t3#
在使用SQLBulkCopy选项将字符串传递给数据库表时,我遇到了类似的问题。我传递的字符串是3个字符,而目标列长度是varchar(20)。我尝试在使用Trim()函数插入DB之前修剪字符串,以检查问题是否是由于字符串中的任何空格(前导和尾随)造成的。修剪完绳子后,它工作得很好。你可以试试text.Trim()
varchar(20)
Trim()
text.Trim()
ktca8awb4#
检查正在执行大容量插入/复制的表中列的大小。varchar或其他字符串列可能需要扩展,或者插入的值需要修剪。列顺序也应与表中的相同。e、 g,将varchar列30的大小增加到50=>ALTER TABLE[dbo]。[TableName]ALTER COLUMN[ColumnName]Varchar(50)
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; }
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。
dl5txlt97#
我只是偶然发现了这一点,使用@b_stil的代码片段,我找到了罪魁祸首列。在进一步的调查中,我认为我需要像@Liji Chandran建议的那样修改列,但我使用的是IExcelDataReader,我无法找到一个简单的方法来验证和修改我的160个列中的每一个。然后我从CSVReader偶然发现了this class, (ValidatingDataReader)类。这个类的有趣之处在于,它给出了源列和目标列的数据长度、错误行,甚至是导致错误的列值。我所做的只是修剪所有(nvarchar、varchar和nchar)列。我刚刚将GetValue方法更改为:
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; }
希望这能帮助某人
q1qsirdb8#
我一直在使用SqlBulkCopy将Access数据库传输到SQL。简单地说,我在SQL中创建每个表,将相应的Access表加载到DataTable中,然后SqlBulkCopy将DataTable复制到相应的SQL表中。因为我使用了一个标准化的函数来实现这一点,所以我没有设置任何ColumnMappings。当没有ColumnMappings时,SqlBulkCopy似乎只是将列0Map到列0,将列1Map到列1,以此类推。在我的例子中,我必须确保Access表中的列顺序与新SQL表中的顺序完全匹配。一旦我做到了,它就按预期运行了。
8条答案
按热度按时间doinxwow1#
我知道这篇帖子很旧,但我遇到了同样的问题,最终找到了一个解决方案,以确定是哪一列导致了问题,并根据需要将其报告回来。我确定SqlException中返回的**
colid
**不是从零开始的,因此需要从中减去1才能获得值。之后,它将用作SqlBulkCopy示例的_sortedColumnMappings
ArrayList的索引,而不是添加到SqlBulkCopy示例的列Map的索引。需要注意的一点是,SqlBulkCopy将在收到第一个错误时停止,因此这可能不是唯一的问题,但至少有助于解决问题。vybvopom2#
excel中的一个数据列(列Id 6)有一个或多个单元格数据超出了数据库中的数据列数据类型长度。
在excel中验证数据。还要验证excel中的数据格式是否符合数据库表模式。
为了避免这种情况,请尝试超过数据库表中字符串数据类型的数据长度。
希望这有帮助。
daupos2t3#
在使用SQLBulkCopy选项将字符串传递给数据库表时,我遇到了类似的问题。我传递的字符串是3个字符,而目标列长度是
varchar(20)
。我尝试在使用Trim()
函数插入DB之前修剪字符串,以检查问题是否是由于字符串中的任何空格(前导和尾随)造成的。修剪完绳子后,它工作得很好。你可以试试
text.Trim()
ktca8awb4#
检查正在执行大容量插入/复制的表中列的大小。varchar或其他字符串列可能需要扩展,或者插入的值需要修剪。列顺序也应与表中的相同。
e、 g,将varchar列30的大小增加到50=>
ALTER TABLE[dbo]。[TableName]ALTER COLUMN[ColumnName]Varchar(50)
dwthyt8l5#
很棒的代码,谢谢分享!
我最终使用反射来获取实际的DataMemberName,以便在出现错误时将其返回给客户端(我在WCF服务中使用了批量存储)。希望其他人会发现我是如何做到这一点的。
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。
dl5txlt97#
我只是偶然发现了这一点,使用@b_stil的代码片段,我找到了罪魁祸首列。在进一步的调查中,我认为我需要像@Liji Chandran建议的那样修改列,但我使用的是IExcelDataReader,我无法找到一个简单的方法来验证和修改我的160个列中的每一个。
然后我从CSVReader偶然发现了this class, (ValidatingDataReader)类。
这个类的有趣之处在于,它给出了源列和目标列的数据长度、错误行,甚至是导致错误的列值。
我所做的只是修剪所有(nvarchar、varchar和nchar)列。
我刚刚将
GetValue
方法更改为:希望这能帮助某人
q1qsirdb8#
我一直在使用SqlBulkCopy将Access数据库传输到SQL。简单地说,我在SQL中创建每个表,将相应的Access表加载到DataTable中,然后SqlBulkCopy将DataTable复制到相应的SQL表中。因为我使用了一个标准化的函数来实现这一点,所以我没有设置任何ColumnMappings。当没有ColumnMappings时,SqlBulkCopy似乎只是将列0Map到列0,将列1Map到列1,以此类推。
在我的例子中,我必须确保Access表中的列顺序与新SQL表中的顺序完全匹配。一旦我做到了,它就按预期运行了。