eklemeye çalışırken hata, dize veya ikili veriler kesilecek


250

Aşağıdaki satırlarla data.bat dosyasını çalıştırıyorum:

Rem Tis batch file will populate tables

cd\program files\Microsoft SQL Server\MSSQL
osql -U sa -P Password -d MyBusiness -i c:\data.sql

Data.sql dosyasının içeriği:

   insert Customers
            (CustomerID, CompanyName, Phone)
             Values('101','Southwinds','19126602729')

Kayıt eklemek için 8 benzer satır daha var.

Ben bu çalıştırdığınızda start> run> cmd> c:\data.bat, bu hata mesajını alıyorum:

1>2>3>4>5>....<1 row affected>
Msg 8152, Level 16, State 4, Server SP1001, Line 1
string or binary data would be truncated.

<1 row affected>

<1 row affected>

<1 row affected>

<1 row affected>

<1 row affected>

<1 row affected>

Ayrıca, ben bir acemi Açıkçası, ama ne Level #ve state #ortalama ve nasıl böyle yukarıdaki gibi hata iletileri görünüyorum: 8152?

Yanıtlar:


609

Gönderen gmmastros cevabı @

Mesajı her gördüğünüzde ....

dize veya ikili veriler kesilir

Kendinizi düşünün ... Alan, verilerimi tutacak kadar büyük DEĞİLDİR.

Müşteri tablosu için tablo yapısını kontrol edin. Bir veya daha fazla alanın uzunluğunun eklemeye çalıştığınız verileri tutacak kadar büyük olmadığını göreceksiniz. Örneğin, Telefon alanı bir varchar (8) alanıysa ve içine 11 karakter girmeye çalışırsanız, bu hatayı alırsınız.


16
Ayrıca, etkilenen alanların tetikleyici içinde olabileceğini unutmayın. Umarım bu bir dahaki sefere bunu hatırlıyorum ...
Kevin Pope

14
Hata ayıklamada hangi alanın kesileceğini görmenin bir yolu var mı?
DailyFrankPeter

Bu hatanın nedeni, sütununuzun sabitlediğiniz uzunluktan sonra verileri tutamamasıdır. Örneğin; Firstname nvarchar(5) 5'ten fazla karakter eklerseniz hatayı alırsınız
Prakash

26

Veri uzunluğu alan uzunluğundan daha kısa olmasına rağmen bu sorunu yaşadım. Sorunun, ana tablodaki bir tetikleyici ile doldurulan ve sütun boyutunun da değiştirilmesi gerektiği başka bir günlük tablosuna (denetim izi için) sahip olduğu ortaya çıktı.


1
Teşekkürler. Benimki, tableA'daki sql sütunun varchar (100) olmasıdır. Ayrıca, sütunun varchar (50) olduğu başka bir tabloya eklenir.
Hnin Htet Htet Aung

1
Benim durumumda da aynı sorun oldu. Bir tetikleyici operasyon suçluydu.
otopilot

19

INSERTİfadelerden birinde, bir dize ( varcharveya nvarchar) sütununa çok uzun bir dize eklemeye çalışıyorsunuz .

INSERTKomut dosyasının sadece bir incelemesi tarafından hangi suçlunun olduğu açık değilse , hata mesajından önce<1 row affected> oluşan satırları sayabilirsiniz . Elde edilen sayı artı bir, ifade numarasını verir. Sizin durumunuzda, hatayı üreten ikinci INSERT gibi görünüyor.


2
Aynı sorunu yaşıyorum, hataya hangi sütunun neden olduğunu nasıl bulabilirim?
Cátia Matos

@ AndréBastos: Belki bunu bir soru olarak gönderebilirsiniz (başka biri daha önce yapmadıysa, bu durumda bir yerde hazır bir cevap olabilir).
Andriy M

11

Verilerinizden bazıları veritabanı sütununuza sığmıyor (küçük). Neyin yanlış olduğunu bulmak kolay değil. C # ve Linq2Sql kullanırsanız, kesilecek alanı listeleyebilirsiniz:

İlk önce yardımcı sınıf oluşturun:

public class SqlTruncationExceptionWithDetails : ArgumentOutOfRangeException
{
    public SqlTruncationExceptionWithDetails(System.Data.SqlClient.SqlException inner, DataContext context)
        : base(inner.Message + " " + GetSqlTruncationExceptionWithDetailsString(context))
    {
    }

    /// <summary>
    /// PArt of code from following link
    /// http://stackoverflow.com/questions/3666954/string-or-binary-data-would-be-truncated-linq-exception-cant-find-which-fiel
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    static string GetSqlTruncationExceptionWithDetailsString(DataContext context)
    {
        StringBuilder sb = new StringBuilder();

        foreach (object update in context.GetChangeSet().Updates)
        {
            FindLongStrings(update, sb);
        }

        foreach (object insert in context.GetChangeSet().Inserts)
        {
            FindLongStrings(insert, sb);
        }
        return sb.ToString();
    }

    public static void FindLongStrings(object testObject, StringBuilder sb)
    {
        foreach (var propInfo in testObject.GetType().GetProperties())
        {
            foreach (System.Data.Linq.Mapping.ColumnAttribute attribute in propInfo.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), true))
            {
                if (attribute.DbType.ToLower().Contains("varchar"))
                {
                    string dbType = attribute.DbType.ToLower();
                    int numberStartIndex = dbType.IndexOf("varchar(") + 8;
                    int numberEndIndex = dbType.IndexOf(")", numberStartIndex);
                    string lengthString = dbType.Substring(numberStartIndex, (numberEndIndex - numberStartIndex));
                    int maxLength = 0;
                    int.TryParse(lengthString, out maxLength);

                    string currentValue = (string)propInfo.GetValue(testObject, null);

                    if (!string.IsNullOrEmpty(currentValue) && maxLength != 0 && currentValue.Length > maxLength)
                    {
                        //string is too long
                        sb.AppendLine(testObject.GetType().Name + "." + propInfo.Name + " " + currentValue + " Max: " + maxLength);
                    }

                }
            }
        }
    }
}

Ardından sarıcıyı SubmitChanges için hazırlayın:

public static class DataContextExtensions
{
    public static void SubmitChangesWithDetailException(this DataContext dataContext)
    {
        //http://stackoverflow.com/questions/3666954/string-or-binary-data-would-be-truncated-linq-exception-cant-find-which-fiel
        try
        {
            //this can failed on data truncation
            dataContext.SubmitChanges();
        }       
        catch (SqlException sqlException) //when (sqlException.Message == "String or binary data would be truncated.")
        {

            if (sqlException.Message == "String or binary data would be truncated.") //only for EN windows - if you are running different window language, invoke the sqlException.getMessage on thread with EN culture
                throw new SqlTruncationExceptionWithDetails(sqlException, dataContext);
            else
                throw;
        }
    }
}

Global özel durum işleyici ve günlük kesme ayrıntılarını hazırlayın:

protected void Application_Error(object sender, EventArgs e)
{
    Exception ex = Server.GetLastError();
    string message = ex.Message;
    //TODO - log to file
}

Son olarak kodu kullanın:

Datamodel.SubmitChangesWithDetailException();

9

Sadece ek bilgi ile katkıda bulunmak istiyorum: Aynı sorunu vardı ve alan gelen veri için yeterince büyük değildi ve bu iş parçacığı bunu çözmek için bana yardımcı oldu (üst cevap her şeyi açıklığa kavuşturuyor).

AMA buna neden olabilecek olası nedenlerin neler olduğunu bilmek çok önemlidir.

Benim durumumda böyle bir alan ile tablo oluşturuyordu:

Select '' as  Period, * From Transactions Into #NewTable

Bu nedenle "Dönem" alanının Sıfır uzunluğu vardı ve Ekle işlemlerinin başarısız olmasına neden oldu. Gelen verinin uzunluğu olan "XXXXXX" olarak değiştirdim ve şimdi düzgün çalıştı (çünkü alan şimdi 6 lentgh değerine sahipti).

Umarım bu aynı sorunu olan herkese yardımcı olur :)


7

Bu hatayı alabileceğiniz başka bir durum şudur:

Aynı hatayla karşılaştım ve nedeni, bir sendikadan veri alan bir INSERT deyiminde sütunların sırasının orijinal tablodan farklı olmasıydı. # Table3 içindeki sırayı a, b, c olarak değiştirirseniz hatayı düzeltirsiniz.

select a, b, c into #table1
from #table0

insert into #table1
    select a, b, c from #table2
    union
    select a, c, b from #table3

7

sql sunucusunda SET ANSI_WARNINGS OFF'u şu şekilde kullanabilirsiniz:

        using (SqlConnection conn = new SqlConnection("Data Source=XRAYGOAT\\SQLEXPRESS;Initial Catalog='Healthy Care';Integrated Security=True"))
        {
            conn.Open();

            using (var trans = conn.BeginTransaction())
            {
                try
                {
                    using cmd = new SqlCommand("", conn, trans))
                    { 

                    cmd.CommandText = "SET ANSI_WARNINGS OFF";
                    cmd.ExecuteNonQuery();

                    cmd.CommandText = "YOUR INSERT HERE";
                    cmd.ExecuteNonQuery();

                    cmd.Parameters.Clear();

                    cmd.CommandText = "SET ANSI_WARNINGS ON";
                    cmd.ExecuteNonQuery();

                    trans.Commit();
                    }
                }
                catch (Exception)
                {

                    trans.Rollback();
                }

            }

            conn.Close();

        }

7

Aynı sorunu yaşadım. Sütunumun uzunluğu çok kısaydı.

Yapabileceğiniz şey veritabanına koymak istediğiniz metni uzatmak veya kısaltmaktır .


7

Ayrıca web uygulama yüzeyinde bu sorun oluştu. Sonunda aynı hata iletisinin belirli bir tablodaki SQL güncelleme deyiminden geldiğini öğrendim.

Son olarak, ilgili geçmiş tablo (lar) ındaki sütun tanımının nvarchar, bazı özel durumlarda orijinal tablo sütun türlerinin uzunluğunu eşlemediğini anladım .


4

Tablodaki sorunlu sütunların boyutunu artırdıktan sonra bile aynı sorunu yaşadım.

tl; dr: İlgili Tablo Türlerindeki eşleşen sütunların uzunluğunun da artırılması gerekebilir.

Benim durumumda, hata, CRM verilerinin bir SQL Server DB veya Azure SQL DB ile senkronize edilmesine izin veren Microsoft Dynamics CRM'deki Veri Dışa Aktarma hizmetinden geliyordu.

Uzun bir araştırmadan sonra Veri Dışa Aktarma hizmetinin Tablo Değerli Parametreler kullanması gerektiği sonucuna vardım :

Geçici bir tablo veya birçok parametre oluşturmadan, Transact-SQL deyimine veya saklı yordam veya işlev gibi bir yordama birden çok veri satırı göndermek için tablo değerli parametreler kullanabilirsiniz.

Yukarıdaki belgelerde de görebileceğiniz gibi, veri alma prosedürünü oluşturmak için Tablo Türleri kullanılır:

CREATE TYPE LocationTableType AS TABLE (...);
CREATE PROCEDURE dbo.usp_InsertProductionLocation
  @TVP LocationTableType READONLY

Ne yazık ki, bir Tablo Tipini değiştirmenin bir yolu yoktur, bu yüzden tamamen bırakılmalı ve yeniden oluşturulmalıdır. Masamın 300'den fazla alanı (😱) olduğundan, tablonun sütun tanımına bağlı olarak karşılık gelen Tablo Türünün oluşturulmasını kolaylaştırmak için bir sorgu oluşturdum (sadece [table_name]tablonuzun adıyla değiştirin ):

SELECT 'CREATE TYPE [table_name]Type AS TABLE (' + STRING_AGG(CAST(field AS VARCHAR(max)), ',' + CHAR(10)) + ');' AS create_type
FROM (
  SELECT TOP 5000 COLUMN_NAME + ' ' + DATA_TYPE
      + IIF(CHARACTER_MAXIMUM_LENGTH IS NULL, '', CONCAT('(', IIF(CHARACTER_MAXIMUM_LENGTH = -1, 'max', CONCAT(CHARACTER_MAXIMUM_LENGTH,'')), ')'))
      + IIF(DATA_TYPE = 'decimal', CONCAT('(', NUMERIC_PRECISION, ',', NUMERIC_SCALE, ')'), '')
      AS field
  FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_NAME = '[table_name]'
  ORDER BY ORDINAL_POSITION) AS T;

Tablo Türünü güncelledikten sonra, Veri Dışa Aktarma hizmeti bir kez daha düzgün çalışmaya başladı! :)


2

Saklı yordamımı yürütmek için çalıştığımda, aynı veri vardı çünkü bazı veri eklemek için gereken sütun boyutu eklemek istediğiniz verilerden daha kısa.

Sütun veri türünün boyutunu artırabilir veya verilerinizin uzunluğunu azaltabilirsiniz.


1

Bu hatanın oluşabileceği başka bir durum SQL Server Management Studio'dur. Tablonuzda "metin" veya "ntext" alanlarınız varsa, ne tür bir alanı güncellediğinizden bağımsız olarak (örneğin bit veya tamsayı). Studio'nun tüm "ntext" alanlarını yüklemediği ve değiştirilen alan yerine TÜM alanları güncellediği anlaşılıyor. Sorunu çözmek için, "metin" veya "ntext" alanlarını Management Studio'daki sorgudan hariç tutun


1
Lütfen virgül, nokta ekleyerek ve dilbilgisi hatalarınızı düzelterek cevabınızı yeniden yazmayı düşünün.
George Pamfilis

Bu cevap bana yardımcı oldu - nvarchar alanlarım yeterince büyük ancak ntext alanım var. Management Studio / SMSS'de bir hata gibi görünüyor.
Sha

0

Kevin Pope'un kabul edilen cevap altındaki yorumu ihtiyacım olan şeydi.

Benim durumumda sorun, masamda bir denetim tablosuna güncelleme / ekleme işlemleri ekleyecek tetikleyiciler tanımlanmıştı, ancak denetim tablosunda VARCHAR(MAX), orijinal tabloda bir sütunun olduğu gibi bir veri türü uyuşmazlığı vardı VARCHAR(1). denetim tablosu, bu yüzden tetikleyiciler benim VARCHAR(1)özgün tablo sütun daha büyük bir şey eklemek ve bu hata iletisini almak başarısız.


0

Bazı yerlerde 8K tahsis edilmiş farklı bir taktik alan kullandım. Burada sadece yaklaşık 50/100 kullanılır.

declare @NVPN_list as table 
nvpn            varchar(50)
,nvpn_revision  varchar(5)
,nvpn_iteration INT
,mpn_lifecycle  varchar(30)
,mfr            varchar(100)
,mpn            varchar(50)
,mpn_revision   varchar(5)
,mpn_iteration  INT
-- ...
) INSERT INTO @NVPN_LIST 
SELECT  left(nvpn           ,50)    as nvpn
        ,left(nvpn_revision ,10)    as nvpn_revision
        ,nvpn_iteration
        ,left(mpn_lifecycle ,30)
        ,left(mfr           ,100)
        ,left(mpn           ,50)
        ,left(mpn_revision  ,5)
        ,mpn_iteration
        ,left(mfr_order_num ,50)
FROM [DASHBOARD].[dbo].[mpnAttributes] (NOLOCK) mpna

Toplam 1M kaydım olduğu için hız istedim ve bunların 28K'sını yükledim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.