Я хочу масово завантажити дані CSV-файлу на SQL-сервер 2005 з коду c #, але я стикаюся з помилкою нижче
Отримав недійсну довжину стовпця від клієнта bcp для colid 6.
при масовій копії записувати на сервер баз даних
Відповіді:
Один із стовпців даних у Excel (стовпець Id 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 із бази даних тераданих. Смішно, оскільки попередній запис oledb у ms sql відмінно обробляв усі перетворення символів без заміни кодування. Справжнє число та відповідний стовпець "Введення в пункт призначення", який ви іноді отримуєте із солідним повідомленням, ні до чого. Це не стовпець, коли ви здійснюєте зворотний відлік зверху відображення або щось подібне. Якби я був Microsoft, я б d буде збентежено надіслати повідомлення про помилку, схоже на те, що воно вказує на стовпець проблеми, коли це не так. Я виявив проблему обґрунтованою, зробивши освічену здогадку, а потім змінивши вхід на відображення на "Ігнорувати", а потім повторіть і подивіться, чи повідомлення не зникло. У моєму випадку та в моєму середовищі я виправив це за допомогою substr ('введення вводу Teradata до розміру символу декларації ms sql для вихідного стовпця. Перевірте та переконайтеся, що ваш вкладений substr поширюється через усі ваші перетворення даних та зіставлення. У моєму у випадку це не сталося, і мені довелося видалити всі мої перетворення даних і зіставлення і почати спочатку. Знову забавно, що OLEDB просто впорався з цим, і ADO.net викинув помилку і мусив мати все це втручання, щоб це працювало. Загалом ви слід використовувати OLEDB, коли ціллю є MS Sql. s, вказуючи на стовпець проблеми, коли це не так. Я виявив проблему обґрунтованою, зробивши освічену здогадку, а потім змінивши вхід на відображення на "Ігнорувати", а потім повторіть і подивіться, чи повідомлення не зникло. У моєму випадку та в моєму середовищі я виправив це за допомогою substr ('введення вводу Teradata до розміру символу декларації ms sql для вихідного стовпця. Перевірте та переконайтеся, що ваш вкладений substr поширюється через усі ваші перетворення даних та зіставлення. У моєму у випадку це не сталося, і мені довелося видалити всі мої перетворення даних і зіставлення і почати спочатку. Знову забавно, що OLEDB просто впорався з цим, і ADO.net викинув помилку і мусив мати все це втручання, щоб це працювало. Загалом ви слід використовувати OLEDB, коли ціллю є MS Sql. s, вказуючи на стовпець проблеми, коли це не так. Я виявив проблему обґрунтованою, зробивши освічену здогадку, а потім змінивши вхід на відображення на "Ігнорувати", а потім повторіть і подивіться, чи повідомлення не зникло. У моєму випадку та в моєму середовищі я виправив це за допомогою substr ('введення вводу Teradata до розміру символу декларації ms sql для вихідного стовпця. Перевірте та переконайтеся, що ваш вкладений substr поширюється через усі ваші перетворення даних та зіставлення. У моєму у випадку це не сталося, і мені довелося видалити всі мої перетворення даних і зіставлення і почати спочатку. Знову забавно, що OLEDB просто впорався з цим, і ADO.net викинув помилку і мусив мати все це втручання, щоб це працювало. Загалом ви слід використовувати OLEDB, коли ціллю є MS Sql. Я виявив проблему обґрунтованою, зробивши освічену здогадку, а потім змінивши вхід на відображення на "Ігнорувати", а потім повторіть і подивіться, чи повідомлення не зникло. У моєму випадку та в моєму середовищі я виправив це за допомогою substr ('введення вводу Teradata до розміру символу декларації ms sql для вихідного стовпця. Перевірте та переконайтеся, що ваш вкладений substr поширюється через усі ваші перетворення даних та зіставлення. У моєму у випадку це не сталося, і мені довелося видалити всі мої перетворення даних і зіставлення і почати спочатку. Знову забавно, що OLEDB просто впорався з цим, і ADO.net викинув помилку і повинен був мати все це втручання, щоб це працювало. Загалом ви слід використовувати OLEDB, коли ціллю є MS Sql. Я виявив проблему обґрунтованою, зробивши освічену здогадку, а потім змінивши вхід на відображення на "Ігнорувати", а потім повторіть і подивіться, чи повідомлення не зникло. У моєму випадку та в моєму середовищі я виправив це за допомогою 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;
}
Сподіваюся, це комусь допомагає