Я хочу выполнить массовую загрузку данных файла csv на sql server 2005 из кода C #, но я сталкиваюсь с ошибкой ниже:
Получена недопустимая длина столбца от клиента bcp для colid 6.
при массовой копии записи на сервер базы данных
Ответы:
Один из столбцов данных в Excel (идентификатор столбца 6) содержит данные одной или нескольких ячеек, которые превышают длину типа данных столбца данных в базе данных.
Проверить данные в Excel. Также проверьте, чтобы формат данных в Excel соответствовал схеме таблицы базы данных.
Чтобы этого избежать, попробуйте превысить длину данных строкового типа данных в таблице базы данных.
Надеюсь это поможет.
Я знаю, что этот пост старый, но я столкнулся с той же проблемой и, наконец, нашел решение, чтобы определить, какой столбец вызывает проблему, и сообщить об этом по мере необходимости. Я определил, что 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;
}
Надеюсь, это кому-то поможет