Csv dosyası verilerini c # kodundan sql server 2005'e toplu yüklemek istiyorum ancak aşağıdaki hatayla karşılaşıyorum -
Colid 6 için bcp istemcisinden geçersiz bir sütun uzunluğu alındı.
veritabanı sunucusuna toplu kopyalama yazıldığında
Yanıtlar:
Excel'deki veri sütunlarından biri (Sütun Kimliği 6), veri tabanındaki veri sütunu veri türü uzunluğunu aşan bir veya daha fazla hücre verisine sahip.
Verileri excel'de doğrulayın. Ayrıca, formatının veritabanı tablosu şemasına uygun olması için excel'deki verileri doğrulayın.
Bunu önlemek için, veritabanı tablosundaki dize veri türünün veri uzunluğunu aşmayı deneyin.
Bu yardımcı olur umarım.
Bu yazının eski olduğunu biliyorum, ancak aynı sorunla karşılaştım ve sonunda hangi sütunun soruna neden olduğunu belirlemek ve gerektiğinde geri bildirmek için bir çözüm buldum. colid
SqlException'da döndürülen değerin sıfır tabanlı olmadığını belirledim, bu yüzden değeri almak için ondan 1 çıkarmanız gerekiyor. Bundan sonra _sortedColumnMappings
, SqlBulkCopy örneğine eklenen sütun eşlemelerinin dizini değil, SqlBulkCopy örneğinin ArrayList dizini olarak kullanılır . Unutulmaması gereken bir şey, SqlBulkCopy'nin alınan ilk hatada duracağıdır, bu nedenle tek sorun bu olmayabilir, ancak en azından anlamaya yardımcı olabilir.
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 seçeneğini kullanarak Veritabanı tablosuna bir dize geçirirken benzer bir sorunla karşılaştım. Geçtiğim dize 3 karakter iken hedef sütun uzunluğu idi varchar(20)
. Trim()
Sorunun dizedeki herhangi bir boşluktan (önde gelen ve sondaki) kaynaklanıp kaynaklanmadığını kontrol etmek için işlevi kullanarak DB'ye eklemeden önce dizeyi kırpmayı denedim . İpi kestikten sonra iyi çalıştı.
Deneyebilirsin text.Trim()
Toplu ekleme / kopyalama yaptığınız tablodaki sütunların boyutunu kontrol edin. varchar veya diğer dize sütunlarının genişletilmesi veya eklediğiniz değerin kırpılması gerekebilir. Sütun sırası da tablodakiyle aynı olmalıdır.
örneğin, varchar sütununun boyutunu 30'dan 50'ye artır =>
DEĞİŞİKLİK TABLOSU [dbo]. [TabloAdı] DEĞİŞTİRME SÜTUNU [SütunAdı] Varchar (50)
Harika bir kod parçası, paylaştığınız için teşekkürler!
Gerçek DataMemberName'i bir hata durumunda bir istemciye geri göndermek için yansımayı kullanmayı bıraktım (WCF hizmetinde toplu kaydetme kullanıyorum). Umarım başka biri bunu nasıl yaptığımı faydalı bulacaktır.
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;
}
Bu hata mesajını çok daha yeni bir ssis sürümüyle aldım (2015 işletmesine kıyasla, ssis 2016 olduğunu düşünüyorum). Burada yorum yapacağım çünkü bu hata mesajını google'da aradığınızda ortaya çıkan ilk referans bu. Kaynak karakter boyutu hedef karakter boyutundan daha büyük olduğunda bunun çoğunlukla karakter sütunlarında olduğunu düşünüyorum. Bu mesajı, teradata veritabanından ms sql'ye ado.net girişi kullanırken aldım. Komik çünkü önceki oledb ms sql'ye yazıyor, kodlama geçersiz kılmaları olmadan tüm karakter dönüşümünü mükemmel bir şekilde ele alıyordu. Colid numarası ve bazen colid mesajıyla aldığınız karşılık gelen Hedef Giriş sütunu # değersizdir. Eşlemenin tepesinden geri saydığınızda veya buna benzer bir şey sütun değildir. Microsoft olsaydım Değilken sorun sütununa işaret ediyor gibi görünen bir hata mesajı vermekten utanabilirsiniz. Bilgiye dayalı bir tahminde bulunarak ve ardından eşlemeyi "Yoksay" olarak değiştirip ardından yeniden çalıştırıp mesajın kaybolup kaybolmadığını görerek sorunu çözdüm. Benim durumumda ve ortamımda bunu substr ('Teradata girdisini çıktı sütunu için ms sql bildiriminin karakter boyutuna ekleyerek' düzelttim. Giriş altlarınızın tüm veri dönüştürmeleri ve eşleştirmelerinde yayıldığını kontrol edin ve emin olun. öyle olmadı ve tüm Veri Dönüştürme ve Eşlemelerimi silip yeniden başlamak zorunda kaldım. Yine komik bir şekilde OLEDB bunu halletti ve ADO.net hatayı attı ve çalışmasını sağlamak için tüm bu müdahaleyi yapmak zorunda kaldı. Genel olarak sen Hedefiniz MS Sql olduğunda OLEDB kullanmalısınız. sorun sütununa işaret etmediği halde. Bilgiye dayalı bir tahminde bulunarak ve ardından eşlemeyi "Yoksay" olarak değiştirip ardından yeniden çalıştırıp mesajın kaybolup kaybolmadığını görerek sorunu çözdüm. Benim durumumda ve ortamımda bunu substr ('Teradata girdisini çıktı sütunu için ms sql bildiriminin karakter boyutuna ekleyerek' düzelttim. Giriş altlarınızın tüm veri dönüştürmeleri ve eşleştirmelerinde yayıldığını kontrol edin ve emin olun. öyle olmadı ve tüm Veri Dönüştürme ve Eşlemelerimi silip yeniden başlamak zorunda kaldım. Yine komik bir şekilde OLEDB bunu halletti ve ADO.net hatayı attı ve çalışmasını sağlamak için tüm bu müdahaleyi yapmak zorunda kaldı. Genel olarak sen Hedefiniz MS Sql olduğunda OLEDB kullanmalısınız. sorun sütununa işaret etmediği halde. Bilgiye dayalı bir tahminde bulunarak ve ardından eşlemeyi "Yoksay" olarak değiştirip ardından yeniden çalıştırıp mesajın kaybolup kaybolmadığını görerek sorunu çözdüm. Benim durumumda ve ortamımda bunu substr ('Teradata girdisini çıktı sütunu için ms sql bildiriminin karakter boyutuna ekleyerek' düzelttim. Giriş altlarınızın tüm veri dönüştürmeleri ve eşleştirmelerinde yayıldığını kontrol edin ve emin olun. öyle olmadı ve tüm Veri Dönüştürme ve Eşlemelerimi silip yeniden başlamak zorunda kaldım. Yine komik bir şekilde OLEDB bunu halletti ve ADO.net hatayı attı ve çalışmasını sağlamak için tüm bu müdahaleyi yapmak zorunda kaldı. Genel olarak sen Hedefiniz MS Sql olduğunda OLEDB kullanmalısınız. Bilgiye dayalı bir tahminde bulunarak ve ardından eşlemeyi "Yoksay" olarak değiştirip ardından yeniden çalıştırıp mesajın kaybolup kaybolmadığını görerek sorunu çözdüm. Benim durumumda ve ortamımda bunu substr ('Teradata girdisini çıktı sütunu için ms sql bildiriminin karakter boyutuna ekleyerek' düzelttim. Giriş altlarınızın tüm veri dönüştürmeleri ve eşleştirmelerinde yayıldığını kontrol edin ve emin olun. öyle olmadı ve tüm Veri Dönüştürme ve Eşlemelerimi silip yeniden başlamak zorunda kaldım. Yine komik bir şekilde OLEDB bunu halletti ve ADO.net hatayı attı ve çalışmasını sağlamak için tüm bu müdahaleyi yapmak zorunda kaldı. Genel olarak sen Hedefiniz MS Sql olduğunda OLEDB kullanmalısınız. Bilgiye dayalı bir tahminde bulunarak ve ardından eşlemeyi "Yoksay" olarak değiştirip ardından yeniden çalıştırıp mesajın kaybolup kaybolmadığını görerek sorunu çözdüm. Benim durumumda ve ortamımda bunu substr ('Teradata girdisini çıktı sütunu için ms sql bildiriminin karakter boyutuna ekleyerek' düzelttim. Giriş altlarınızın tüm veri dönüştürmeleri ve eşleştirmelerinde yayıldığını kontrol edin ve emin olun. öyle olmadı ve tüm Veri Dönüştürme ve Eşlemelerimi silip yeniden başlamak zorunda kaldım. Yine komik bir şekilde OLEDB bunu halletti ve ADO.net hatayı attı ve çalışmasını sağlamak için tüm bu müdahaleyi yapmak zorunda kaldı. Genel olarak sen Hedefiniz MS Sql olduğunda OLEDB kullanmalısınız. s ve Eşlemeler ve baştan başlayın. OLEDB'nin bunu halletmesi ve ADO.net'in hatayı atması ve çalışmasını sağlamak için tüm bu müdahaleye sahip olması yine komikti. Genel olarak, hedefiniz MS Sql olduğunda OLEDB kullanmalısınız. s ve Eşlemeler ve baştan başlayın. OLEDB'nin bunu halletmesi ve ADO.net'in hatayı atması ve çalışmasını sağlamak için tüm bu müdahaleye sahip olması yine komikti. Genel olarak, hedefiniz MS Sql olduğunda OLEDB kullanmalısınız.
Buna az önce tökezledim ve @ b_stil'in pasajını kullanarak suçlu sütununu bulabildim. Daha fazla araştırmada, sütunu @Liji Chandran'ın önerdiği gibi kırpmam gerektiğini düşündüm, ancak IExcelDataReader kullanıyordum ve 160 sütunumun her birini doğrulamanın ve düzeltmenin kolay bir yolunu bulamadım.
Sonra CSVReader'dan bu sınıfa, (ValidatingDataReader) sınıfına rastladım .
Bu sınıfla ilgili ilginç olan şey, size kaynak ve hedef sütunlarının veri uzunluğunu, suçlu satırı ve hatta hataya neden olan sütun değerini vermesidir.
Tek yaptığım tüm (nvarchar, varchar, char ve nchar) sütunları kırpmaktı.
Yöntemimi şununla değiştirdim 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;
}
Umarım bu birine yardımcı olur