Получена недопустимая длина столбца от клиента bcp для colid 6

87

Я хочу выполнить массовую загрузку данных файла csv на sql server 2005 из кода C #, но я сталкиваюсь с ошибкой ниже:

Получена недопустимая длина столбца от клиента bcp для colid 6.

при массовой копии записи на сервер базы данных

Сана Сана
источник

Ответы:

69

Один из столбцов данных в Excel (идентификатор столбца 6) содержит данные одной или нескольких ячеек, которые превышают длину типа данных столбца данных в базе данных.

Проверить данные в Excel. Также проверьте, чтобы формат данных в Excel соответствовал схеме таблицы базы данных.

Чтобы этого избежать, попробуйте превысить длину данных строкового типа данных в таблице базы данных.

Надеюсь это поможет.

Динеш
источник
1
В частности, если у вас есть столбцы, VARCHAR которых меньше 4, следите за тем, чтобы NULL в ваших данных не был неправильно истолкован как строка из 4 символов «NULL»
CrazyPyro
195

Я знаю, что этот пост старый, но я столкнулся с той же проблемой и, наконец, нашел решение, чтобы определить, какой столбец вызывает проблему, и сообщить об этом по мере необходимости. Я определил, что colidвозвращаемое в SqlException значение не равно нулю, поэтому вам нужно вычесть из него 1, чтобы получить значение. После этого он используется в качестве индекса _sortedColumnMappingsArrayList экземпляра 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;
}
b_stil
источник
4
Это работает очень хорошо, спасибо за отправку.
Стивен
1
Вы знаете, можно ли также получить номер строки?
Герхард Пауэлл
2
DataFormatException - это настраиваемое исключение, поэтому я могу сообщить о проблеме как о недопустимой длине столбца. Я еще не смог понять, как получить номер строки.
b_stil 02
1
Отличное решение, не хватает только ловушки sqlTran.RollBack ();
pqsk
8
Для большинства это может быть очевидно очевидным, но «colid, который возвращается в SqlException, не основан на нуле», помог мне избавиться от этого.
panhandel
4

Я столкнулся с аналогичной проблемой при передаче строки в таблицу базы данных с использованием параметра SQL BulkCopy. Строка, которую я передавал, состояла из 3 символов, тогда как длина столбца назначения была varchar(20). Я попытался обрезать строку перед вставкой в ​​БД с помощью Trim()функции, чтобы проверить, не связана ли проблема с каким-либо пробелом (ведущим и конечным) в строке. После обрезки струны все заработало.

Можешь попробовать text.Trim()

Лиджи Чандран
источник
Это здорово, большое спасибо! Это было точной причиной и в моем случае - конечный пробел и, как следствие, превышение длины столбца.
aleor 02
Если строка может быть нулевой, используйте текст? .Trim ()
Чарльз Плагер,
1

Проверьте размер столбцов в таблице, в которой вы выполняете массовую вставку / копирование. столбцы varchar или другие строковые могут нуждаться в расширении или значение, которое вы вставляете, должно быть обрезано. Порядок столбцов также должен быть таким же, как в таблице.

например, увеличить размер столбца varchar 30 до 50 =>

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

Налан Мадхесваран
источник
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;
}

инфоцид
источник
Как это можно реализовать?
Apollo
0

Я получил это сообщение об ошибке с гораздо более новой версией 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.

ВозрождениеЧеловек
источник
0

Я только что наткнулся на это и, используя фрагмент @ 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;
    }

Надеюсь, это кому-то поможет

Ахмад Тиджани
источник