Quero fazer o upload em massa dos dados do arquivo csv para o sql server 2005 a partir do código c #, mas estou encontrando o erro a seguir -
Recebeu um comprimento de coluna inválido do cliente bcp para colid 6.
quando a cópia em massa grava no servidor de banco de dados
c#
.net
sql-server
database
sql-server-2005
Sana Sana
fonte
fonte
Sei que esta postagem é antiga, mas encontrei o mesmo problema e finalmente descobri uma solução para determinar qual coluna estava causando o problema e relatar quando necessário. Eu determinei que
colid
retornado no SqlException não é baseado em zero, então você precisa subtrair 1 dele para obter o valor. Depois disso, ele é usado como o índice da_sortedColumnMappings
ArrayList da instância SqlBulkCopy e não o índice dos mapeamentos de coluna que foram adicionados à instância SqlBulkCopy. Uma coisa a notar é que SqlBulkCopy irá parar no primeiro erro recebido, então este pode não ser o único problema, mas pelo menos ajuda a descobri-lo.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; }
fonte
Enfrentei um tipo de problema semelhante ao passar uma string para a tabela de banco de dados usando a opção SQL BulkCopy. A string que eu estava passando era de 3 caracteres, enquanto o comprimento da coluna de destino era
varchar(20)
. Tentei cortar a string antes de inseri-la no banco de dados usando aTrim()
função para verificar se o problema era devido a algum espaço (à esquerda e à direita) na string. Depois de cortar a corda, funcionou bem.Podes tentar
text.Trim()
fonte
Verifique o tamanho das colunas na tabela em que você está inserindo / copiando em massa. o varchar ou outras colunas de string podem precisar ser estendidas ou o valor que você está inserindo precisa ser aparado. A ordem das colunas também deve ser a mesma da tabela.
por exemplo, aumentar o tamanho da coluna varchar 30 para 50 =>
ALTER TABLE [dbo]. [TableName] ALTER COLUMN [ColumnName] Varchar (50)
fonte
Ótimo código, obrigado por compartilhar!
Acabei usando reflexão para fazer o DataMemberName real retornar a um cliente em um erro (estou usando salvamento em massa em um serviço WCF). Espero que outra pessoa descubra como fiz isso útil.
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; }
fonte
Recebi esta mensagem de erro com uma versão ssis muito mais recente (vs 2015 enterprise, acho que é ssis 2016). Vou comentar aqui porque esta é a primeira referência que surge quando você google esta mensagem de erro. Eu acho que isso acontece principalmente com colunas de caracteres quando o tamanho do caractere de origem é maior do que o tamanho do caractere de destino. Recebi esta mensagem quando estava usando uma entrada ado.net para ms sql de um banco de dados teradata. Engraçado porque as gravações de oledb anteriores em ms sql tratavam perfeitamente de todas as conversões de caracteres, sem substituições de codificação. O número colid e a coluna de entrada de destino correspondente # que você às vezes recebe com a mensagem colid são inúteis. Não é a coluna quando você faz a contagem regressiva do topo do mapeamento ou algo parecido. Se eu fosse a microsoft, eu ' Você teria vergonha de fornecer uma mensagem de erro que parecesse estar apontando para a coluna do problema, quando não está. Eu achei o problema colid fazendo uma suposição educada e, em seguida, alterando a entrada para o mapeamento para "Ignorar" e, em seguida, execute novamente para ver se a mensagem foi embora. No meu caso e no meu ambiente, corrigi-lo por substr ('ing a entrada Teradata para o tamanho do caractere da declaração ms sql para a coluna de saída. Verifique e certifique-se de que seu substr de entrada se propaga através de todas as conversões de dados e mapeamentos. caso isso não acontecesse e eu tive que deletar todos os meus Data Conversion's e Mappings e começar tudo de novo. Mais uma vez engraçado que OLEDB acabou de lidar com isso e ADO.net lançou o erro e teve que ter toda esta intervenção para fazer funcionar. deve usar OLEDB quando seu destino for MS Sql. s apontando para a coluna do problema quando não está. Eu achei o problema colid fazendo uma suposição educada e, em seguida, alterando a entrada para o mapeamento para "Ignorar" e, em seguida, execute novamente para ver se a mensagem foi embora. No meu caso e no meu ambiente, corrigi-lo por substr ('ing a entrada Teradata para o tamanho do caractere da declaração ms sql para a coluna de saída. Verifique e certifique-se de que seu substr de entrada se propaga através de todas as conversões de dados e mapeamentos. caso isso não acontecesse e eu tive que deletar todos os meus Data Conversion's e Mappings e começar tudo de novo. Mais uma vez engraçado que OLEDB acabou de lidar com isso e ADO.net lançou o erro e teve que ter toda esta intervenção para fazer funcionar. deve usar OLEDB quando seu destino for MS Sql. s apontando para a coluna do problema quando não está. Eu achei o problema colid fazendo uma suposição educada e, em seguida, alterando a entrada para o mapeamento para "Ignorar" e, em seguida, execute novamente para ver se a mensagem foi embora. No meu caso e no meu ambiente, corrigi-lo por substr ('ing a entrada Teradata para o tamanho do caractere da declaração ms sql para a coluna de saída. Verifique e certifique-se de que seu substr de entrada se propaga através de todas as conversões de dados e mapeamentos. caso isso não acontecesse e eu tive que deletar todos os meus Data Conversion's e Mappings e começar tudo de novo. Mais uma vez engraçado que OLEDB acabou de lidar com isso e ADO.net lançou o erro e teve que ter toda esta intervenção para fazer funcionar. deve usar OLEDB quando seu destino for MS Sql. Eu achei o problema colid fazendo uma suposição educada e, em seguida, alterando a entrada para o mapeamento para "Ignorar" e, em seguida, execute novamente para ver se a mensagem foi embora. No meu caso e no meu ambiente, corrigi-lo por substr ('ing a entrada Teradata para o tamanho do caractere da declaração ms sql para a coluna de saída. Verifique e certifique-se de que seu substr de entrada se propaga através de todas as conversões de dados e mapeamentos. caso isso não acontecesse e eu tive que deletar todos os meus Data Conversion's e Mappings e começar tudo de novo. Mais uma vez engraçado que OLEDB acabou de lidar com isso e ADO.net lançou o erro e teve que ter toda essa intervenção para fazer funcionar. deve usar OLEDB quando seu destino for MS Sql. Eu achei o problema colid fazendo uma suposição educada e, em seguida, alterando a entrada para o mapeamento para "Ignorar" e, em seguida, execute novamente para ver se a mensagem foi embora. No meu caso e no meu ambiente, corrigi-lo por substr ('ing a entrada Teradata para o tamanho do caractere da declaração ms sql para a coluna de saída. Verifique e certifique-se de que seu substr de entrada se propaga através de todas as conversões de dados e mapeamentos. caso isso não acontecesse e eu tive que deletar todos os meus Data Conversion's e Mappings e começar tudo de novo. Mais uma vez engraçado que OLEDB acabou de lidar com isso e ADO.net lançou o erro e teve que ter toda esta intervenção para fazer funcionar. deve usar OLEDB quando seu destino for MS Sql. se mapeamentos e comece novamente. Mais uma vez, engraçado que o OLEDB tenha acabado de lidar com isso e o ADO.net lançou o erro e teve que ter toda essa intervenção para fazer funcionar. Em geral, você deve usar OLEDB quando seu destino for MS Sql. se mapeamentos e comece novamente. Mais uma vez, engraçado que o OLEDB tenha acabado de lidar com isso e o ADO.net lançou o erro e teve que ter toda essa intervenção para fazer funcionar. Em geral, você deve usar OLEDB quando seu destino for MS Sql.
fonte
Acabei de descobrir isso e usando o snippet de @b_stil, consegui descobrir a coluna do culpado. E em uma investigação mais aprofundada, percebi que precisava cortar a coluna exatamente como @Liji Chandran sugeriu, mas estava usando IExcelDataReader e não conseguia descobrir uma maneira fácil de validar e cortar cada uma das minhas 160 colunas.
Então me deparei com esta classe, (ValidatingDataReader) classe de CSVReader .
O interessante sobre essa classe é que ela fornece o comprimento dos dados das colunas de origem e destino, a linha culpada e até mesmo o valor da coluna que está causando o erro.
Tudo o que fiz foi apenas cortar todas as colunas (nvarchar, varchar, char e nchar).
Acabei de mudar meu
GetValue
método para este: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; }
Espero que isso ajude alguém
fonte