Je souhaite télécharger en bloc des données de fichier csv sur le serveur SQL 2005 à partir du code c # mais je rencontre l'erreur ci-dessous -
Reçu une longueur de colonne non valide du client bcp pour colid 6.
lors de l'écriture d'une copie en bloc sur le serveur de base de données
la source
Je sais que cet article est ancien, mais j'ai rencontré le même problème et j'ai finalement trouvé une solution pour déterminer quelle colonne était à l'origine du problème et le signaler au besoin. J'ai déterminé que le
colid
retour dans SqlException n'est pas basé sur zéro, vous devez donc en soustraire 1 pour obtenir la valeur. Après cela, il est utilisé comme index de_sortedColumnMappings
ArrayList de l'instance SqlBulkCopy et non comme index des mappages de colonnes qui ont été ajoutés à l'instance SqlBulkCopy. Une chose à noter est que SqlBulkCopy s'arrêtera à la première erreur reçue, ce n'est donc peut-être pas le seul problème, mais cela aide au moins à le résoudre.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; }
la source
J'ai rencontré un problème similaire lors de la transmission d'une chaîne à la table Database à l'aide de l'option SQL BulkCopy. La chaîne que je passais était de 3 caractères alors que la longueur de la colonne de destination était
varchar(20)
. J'ai essayé de couper la chaîne avant de l'insérer dans DB en utilisant laTrim()
fonction pour vérifier si le problème était dû à un espace (au début et à la fin) dans la chaîne. Après avoir coupé la chaîne, cela a bien fonctionné.Tu peux essayer
text.Trim()
la source
Vérifiez la taille des colonnes du tableau que vous effectuez une insertion / copie en bloc. le varchar ou d'autres colonnes de chaîne doivent peut-être être étendues ou la valeur que vous insérez doit être ajustée. L'ordre des colonnes doit également être le même que dans le tableau.
Par exemple, augmenter la taille de la colonne varchar 30 à 50 =>
ALTER TABLE [dbo]. [TableName] ALTER COLUMN [ColumnName] Varchar (50)
la source
Super morceau de code, merci pour le partage!
J'ai fini par utiliser la réflexion pour obtenir le DataMemberName réel à renvoyer à un client en cas d'erreur (j'utilise une sauvegarde en bloc dans un service WCF). J'espère que quelqu'un d'autre trouvera comment je l'ai fait utile.
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; }
la source
J'ai reçu ce message d'erreur avec une version ssis beaucoup plus récente (par rapport à 2015 entreprise, je pense que c'est ssis 2016). Je vais commenter ici car c'est la première référence qui apparaît lorsque vous recherchez ce message d'erreur sur Google. Je pense que cela se produit principalement avec les colonnes de caractères lorsque la taille du caractère source est supérieure à la taille du caractère cible. J'ai reçu ce message lorsque j'utilisais une entrée ado.net dans ms sql à partir d'une base de données teradata. C'est drôle parce que le précédent oledb écrit dans ms sql gère parfaitement toute la conversion de caractères sans remplacement de codage. Le numéro de colid et la colonne d'entrée de destination correspondante # que vous obtenez parfois avec le message colid sont sans valeur. Ce n'est pas la colonne lorsque vous comptez à rebours depuis le haut du mappage ou quoi que ce soit du genre. Si j'étais Microsoft, je ' d être gêné de donner un message d'erreur qui semble pointer vers la colonne du problème alors que ce n'est pas le cas. J'ai trouvé le problème colide en faisant une supposition éclairée, puis en changeant l'entrée du mappage sur "Ignorer", puis en réexécutant et voir si le message a disparu. Dans mon cas et dans mon environnement, je l'ai corrigé par substr ('ing l'entrée Teradata à la taille de caractère de la déclaration ms sql pour la colonne de sortie. Vérifiez et assurez-vous que vos substrats d'entrée se propagent à travers toutes vos conversions et mappages de données. Dans mon si ce n'est pas le cas et j'ai dû supprimer toutes mes conversions et mappages de données et recommencer. Encore une fois drôle que OLEDB vient de le gérer et ADO.net a jeté l'erreur et a dû avoir toute cette intervention pour que cela fonctionne. En général, vous devrait utiliser OLEDB lorsque votre cible est MS Sql. s pointant vers la colonne du problème quand ce n'est pas le cas. J'ai trouvé le problème colide en faisant une supposition éclairée, puis en changeant l'entrée du mappage sur "Ignorer", puis en réexécutant et voir si le message avait disparu. Dans mon cas et dans mon environnement, je l'ai corrigé par substr ('ing l'entrée Teradata à la taille de caractère de la déclaration ms sql pour la colonne de sortie. Vérifiez et assurez-vous que vos substrats d'entrée se propagent à travers toutes vos conversions et mappages de données. Dans mon si ce n'est pas le cas et j'ai dû supprimer toutes mes conversions et mappages de données et recommencer. Encore une fois drôle que OLEDB vient de le gérer et ADO.net a jeté l'erreur et a dû avoir toute cette intervention pour que cela fonctionne. En général, vous devrait utiliser OLEDB lorsque votre cible est MS Sql. s pointant vers la colonne du problème quand ce n'est pas le cas. J'ai trouvé le problème colide en faisant une supposition éclairée, puis en changeant l'entrée du mappage sur "Ignorer", puis en réexécutant et voir si le message a disparu. Dans mon cas et dans mon environnement, je l'ai corrigé par substr ('ing l'entrée Teradata à la taille de caractère de la déclaration ms sql pour la colonne de sortie. Vérifiez et assurez-vous que vos substrats d'entrée se propagent à travers toutes vos conversions et mappages de données. Dans mon si ce n'est pas le cas et j'ai dû supprimer toutes mes conversions et mappages de données et recommencer. Encore une fois drôle que OLEDB vient de le gérer et ADO.net a jeté l'erreur et a dû avoir toute cette intervention pour que cela fonctionne. En général, vous devrait utiliser OLEDB lorsque votre cible est MS Sql. J'ai trouvé le problème colide en faisant une supposition éclairée, puis en changeant l'entrée du mappage sur "Ignorer", puis en réexécutant et voir si le message avait disparu. Dans mon cas et dans mon environnement, je l'ai corrigé par substr ('ing l'entrée Teradata à la taille de caractère de la déclaration ms sql pour la colonne de sortie. Vérifiez et assurez-vous que vos substrats d'entrée se propagent à travers toutes vos conversions et mappages de données. Dans mon si ce n'est pas le cas et j'ai dû supprimer toutes mes conversions et mappages de données et recommencer. Encore une fois drôle que OLEDB vient de le gérer et ADO.net a jeté l'erreur et a dû avoir toute cette intervention pour que cela fonctionne. En général, vous devrait utiliser OLEDB lorsque votre cible est MS Sql. J'ai trouvé le problème colide en faisant une supposition éclairée, puis en modifiant l'entrée du mappage sur "Ignorer", puis en réexécutant et voir si le message a disparu. Dans mon cas et dans mon environnement, je l'ai corrigé par substr ('ing l'entrée Teradata à la taille de caractère de la déclaration ms sql pour la colonne de sortie. Vérifiez et assurez-vous que vos substrats d'entrée se propagent à travers toutes vos conversions et mappages de données. Dans mon si ce n'est pas le cas et j'ai dû supprimer toutes mes conversions et mappages de données et recommencer. Encore une fois drôle que OLEDB vient de le gérer et ADO.net a jeté l'erreur et a dû avoir toute cette intervention pour que cela fonctionne. devrait utiliser OLEDB lorsque votre cible est MS Sql. s et Mappings et recommencer. Encore une fois drôle, OLEDB vient de le gérer et ADO.net a jeté l'erreur et a dû avoir toute cette intervention pour que cela fonctionne. En général, vous devez utiliser OLEDB lorsque votre cible est MS Sql. s et Mappings et recommencer. Encore une fois drôle, OLEDB vient de le gérer et ADO.net a jeté l'erreur et a dû avoir toute cette intervention pour que cela fonctionne. En général, vous devez utiliser OLEDB lorsque votre cible est MS Sql.
la source
Je viens de tomber dessus et en utilisant l'extrait de @ b_stil, j'ai pu comprendre la colonne du coupable. Et après une enquête plus approfondie, j'ai pensé que je devais couper la colonne comme @Liji Chandran le suggérait, mais j'utilisais IExcelDataReader et je ne pouvais pas trouver un moyen facile de valider et de couper chacune de mes 160 colonnes.
Ensuite, je suis tombé sur cette classe, la classe (ValidatingDataReader) de CSVReader .
Ce qui est intéressant à propos de cette classe, c'est qu'elle vous donne la longueur des données des colonnes source et de destination, la ligne coupable et même la valeur de la colonne à l'origine de l'erreur.
Tout ce que j'ai fait, c'est simplement couper toutes les colonnes (nvarchar, varchar, char et nchar).
Je viens de changer ma
GetValue
méthode pour ceci: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; }
J'espère que cela aide quelqu'un
la source