Я хочу выполнить массовую загрузку данных файла csv на sql server 2005 из кода C #, но я сталкиваюсь с ошибкой ниже:
Получена недопустимая длина столбца от клиента bcp для colid 6.
при массовой копии записи на сервер базы данных
c#
.net
sql-server
database
sql-server-2005
Сана Сана
источник
источник
Я знаю, что этот пост старый, но я столкнулся с той же проблемой и, наконец, нашел решение, чтобы определить, какой столбец вызывает проблему, и сообщить об этом по мере необходимости. Я определил, что
colid
возвращаемое в SqlException значение не равно нулю, поэтому вам нужно вычесть из него 1, чтобы получить значение. После этого он используется в качестве индекса_sortedColumnMappings
ArrayList экземпляра SqlBulkCopy, а не индекса сопоставлений столбцов, которые были добавлены в экземпляр 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; }
источник
Я столкнулся с аналогичной проблемой при передаче строки в таблицу базы данных с использованием параметра SQL BulkCopy. Строка, которую я передавал, состояла из 3 символов, тогда как длина столбца назначения была
varchar(20)
. Я попытался обрезать строку перед вставкой в БД с помощьюTrim()
функции, чтобы проверить, не связана ли проблема с каким-либо пробелом (ведущим и конечным) в строке. После обрезки струны все заработало.Можешь попробовать
text.Trim()
источник
Проверьте размер столбцов в таблице, в которой вы выполняете массовую вставку / копирование. столбцы varchar или другие строковые могут нуждаться в расширении или значение, которое вы вставляете, должно быть обрезано. Порядок столбцов также должен быть таким же, как в таблице.
например, увеличить размер столбца varchar 30 до 50 =>
ALTER TABLE [dbo]. [TableName] ALTER COLUMN [ColumnName] Varchar (50)
источник
Отличный фрагмент кода, спасибо, что поделились!
В итоге я использовал отражение, чтобы получить фактическое имя 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; }
источник
Я получил это сообщение об ошибке с гораздо более новой версией ssis (по сравнению с 2015 годом, я думаю, что это ssis 2016). Я прокомментирую здесь, потому что это первая ссылка, которая появляется, когда вы гуглите это сообщение об ошибке. Я думаю, что это происходит в основном с символьными столбцами, когда размер исходного символа больше, чем размер целевого символа. Я получил это сообщение, когда использовал ввод ado.net в ms sql из базы данных teradata. Забавно, потому что предыдущий oledb записывает в ms sql отлично справляется со всем преобразованием символов без переопределения кодирования. Номер colid и соответствующий столбец # ввода назначения, который вы иногда получаете с сообщением colid, бесполезны. Это не столбец, когда вы ведете обратный отсчет от вершины сопоставления или что-то в этом роде. Если бы я был Microsoft, я бы Я стесняюсь выдавать сообщение об ошибке, которое выглядит так, как будто оно указывает на столбец проблемы, когда это не так. Я обнаружил проблему colid, сделав обоснованное предположение, а затем изменив вход для сопоставления на «Игнорировать», а затем повторно запустил и посмотрел, исчезло ли сообщение. В моем случае и в моей среде я исправил это с помощью substr ('при вводе Teradata в размер символа объявления ms sql для выходного столбца. Проверьте и убедитесь, что ваш входной substr распространяется через все ваши преобразования и сопоставления данных. в случае, если этого не произошло, и мне пришлось удалить все мои преобразования данных и сопоставления и начать заново. Снова забавно, что OLEDB просто обработал это, а ADO.net выдал ошибку и пришлось все это вмешательство, чтобы заставить его работать. В общем, вы следует использовать OLEDB, если ваша цель - MS Sql. указывает на проблемный столбец, когда это не так. Я обнаружил проблему colid, сделав обоснованное предположение, а затем изменив вход для сопоставления на «Игнорировать», а затем перезапустив его и посмотреть, исчезло ли сообщение. В моем случае и в моей среде я исправил это с помощью substr ('при вводе Teradata в размер символа объявления ms sql для выходного столбца. Проверьте и убедитесь, что ваш входной substr распространяется через все ваши преобразования и сопоставления данных. в случае, если этого не произошло, и мне пришлось удалить все мои преобразования данных и сопоставления и начать заново. Снова забавно, что OLEDB просто справился с этим, а ADO.net выдал ошибку и потребовалось все это вмешательство, чтобы заставить его работать. В общем, вы следует использовать OLEDB, если ваша цель - MS Sql. указывает на проблемный столбец, когда это не так. Я обнаружил проблему colid, сделав обоснованное предположение, а затем изменив вход для сопоставления на «Игнорировать», а затем повторно запустил и посмотрел, исчезло ли сообщение. В моем случае и в моей среде я исправил это с помощью substr ('при вводе Teradata в размер символа объявления ms sql для выходного столбца. Проверьте и убедитесь, что ваш входной substr распространяется через все преобразования и сопоставления данных. в случае, если этого не произошло, и мне пришлось удалить все мои преобразования данных и сопоставления и начать заново. Снова забавно, что OLEDB просто справился с этим, а ADO.net выдал ошибку и потребовалось все это вмешательство, чтобы заставить его работать. В общем, вы следует использовать OLEDB, если ваша цель - MS Sql. Я обнаружил проблему colid, сделав обоснованное предположение, а затем изменив вход для сопоставления на «Игнорировать», а затем повторно запустил и посмотрел, исчезло ли сообщение. В моем случае и в моей среде я исправил это с помощью substr ('при вводе Teradata в размер символа объявления ms sql для выходного столбца. Проверьте и убедитесь, что ваш входной substr распространяется через все преобразования и сопоставления данных. в случае, если этого не произошло, и мне пришлось удалить все мои преобразования данных и сопоставления и начать заново. Снова забавно, что OLEDB просто справился с этим, а ADO.net выдал ошибку и потребовалось все это вмешательство, чтобы заставить его работать. В общем, вы следует использовать OLEDB, если ваша цель - MS Sql. Я обнаружил проблему colid, сделав обоснованное предположение, а затем изменив вход для сопоставления на «Игнорировать», а затем повторно запустил и посмотрел, исчезло ли сообщение. В моем случае и в моей среде я исправил это с помощью substr ('при вводе Teradata в размер символа объявления ms sql для выходного столбца. Проверьте и убедитесь, что ваш входной substr распространяется через все преобразования и сопоставления данных. в случае, если этого не произошло, и мне пришлось удалить все мои преобразования данных и сопоставления и начать заново. Снова забавно, что OLEDB просто обработал это, а ADO.net выдал ошибку и пришлось все это вмешательство, чтобы заставить его работать. В общем, вы следует использовать OLEDB, если ваша цель - MS Sql. s и Mappings и начните заново. Снова забавно, что OLEDB просто справился с этим, а ADO.net выдал ошибку и потребовалось все это вмешательство, чтобы заставить его работать. В общем, вы должны использовать OLEDB, когда вашей целью является MS Sql. s и Mappings и начните заново. Снова забавно, что OLEDB просто справился с этим, а ADO.net выдал ошибку и потребовалось все это вмешательство, чтобы заставить его работать. В общем, вы должны использовать OLEDB, когда вашей целью является MS Sql.
источник
Я только что наткнулся на это и, используя фрагмент @ b_stil, смог определить столбец виновника. И в ходе дальнейшего расследования я решил, что мне нужно обрезать столбец, как предложил @Liji Chandran, но я использовал IExcelDataReader, и я не мог найти простой способ проверить и обрезать каждый из моих 160 столбцов.
Затем я наткнулся на этот класс (ValidatingDataReader) из CSVReader .
Что интересно в этом классе, так это то, что он дает вам длину данных исходных и целевых столбцов, виновную строку и даже значение столбца, вызывающее ошибку.
Все, что я сделал, это просто обрезал все столбцы (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; }
Надеюсь, это кому-то поможет
источник