błąd, ciąg lub dane binarne zostaną obcięte podczas próby wstawienia

250

Korzystam z pliku data.bat z następującymi wierszami:

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

Zawartość pliku data.sql to:

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

Jest jeszcze 8 podobnych linii do dodawania rekordów.

Gdy uruchomię to z start> run> cmd> c:\data.bat, otrzymuję komunikat o błędzie:

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>

Również jestem nowicjuszem oczywiście, ale co zrobić Level #, a state #średni, i jak mogę sprawdzić komunikaty o błędach, takich jak ten powyżej: 8152?

karthik
źródło

Odpowiedzi:

609

Z odpowiedzi @ gmmastros

Kiedykolwiek zobaczysz komunikat ...

ciąg znaków lub dane binarne będą obcięte

Pomyśl o sobie ... Pole NIE jest wystarczająco duże, aby pomieścić moje dane.

Sprawdź strukturę tabeli dla tabeli klientów. Myślę, że przekonasz się, że długość jednego lub więcej pól NIE jest wystarczająco duża, aby pomieścić dane, które próbujesz wstawić. Na przykład, jeśli pole Telefon jest polem varchar (8) i spróbujesz wstawić do niego 11 znaków, pojawi się ten błąd.

karthik
źródło
16
Należy również pamiętać, że zmienione pola mogą być wyzwalaczem. Mam nadzieję, że pamiętam to, kiedy następnym razem to się stanie ...
Kevin Pope
14
Czy jest jakiś sposób na sprawdzenie w debugowaniu, które pole zostanie obcięte?
DailyFrankPeter,
Ten błąd jest spowodowany tym, że kolumna nie może przechowywać danych po ustalonej długości. Na przykład; Firstname nvarchar(5) Jeśli wstawisz więcej niż 5 znaków, pojawi się błąd
Prakash
26

Miałem ten problem, chociaż długość danych była mniejsza niż długość pola. Okazało się, że problemem była kolejna tabela dziennika (dla ścieżki audytu), wypełniona wyzwalaczem w głównej tabeli, w której również trzeba było zmienić rozmiar kolumny.

alterfox
źródło
1
Dzięki. Mój był, ponieważ kolumna sql w tabeli A jest varchar (100). Wstawia także do innej tabeli, w której kolumna jest varchar (50).
Hnin Htet Htet Aung
1
Ten sam problem zdarzył się również w moim przypadku. Winowajcą była operacja spustowa.
autopilot
19

W jednej z INSERTinstrukcji próbujesz wstawić zbyt długi ciąg do ciągu (varcharnvarchar kolumny lub ).

Jeśli nie jest oczywiste INSERT, kto jest sprawcą, wystarczy samo spojrzenie na skrypt, możesz policzyć <1 row affected>linie, które występują przed komunikatem o błędzie. Otrzymana liczba plus jeden daje numer wyciągu. W twoim przypadku wydaje się, że to drugi WSTAW, który powoduje błąd.

Andriy M.
źródło
2
Mam ten sam problem, jak znaleźć, która kolumna powoduje błąd?
Cátia Matos
@ AndréBastos: Być może możesz zadać to pytanie (chyba że ktoś inny już to zrobił, w którym to przypadku może być gdzieś gotowa odpowiedź).
Andriy M
11

Niektóre dane nie mieszczą się w kolumnie bazy danych (małe). Nie jest łatwo znaleźć to, co jest złe. Jeśli używasz C # i Linq2Sql, możesz wymienić pole, które byłoby obcięte:

Najpierw utwórz klasę pomocnika:

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);
                    }

                }
            }
        }
    }
}

Następnie przygotuj opakowanie dla funkcji Prześlij zmiany:

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;
        }
    }
}

Przygotuj globalną procedurę obsługi wyjątków i szczegóły obcinania dziennika:

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

Na koniec użyj kodu:

Datamodel.SubmitChangesWithDetailException();
Tomas Kubes
źródło
9

Chcę tylko przekazać dodatkowe informacje: miałem ten sam problem i to dlatego, że pole nie było wystarczająco duże dla przychodzących danych i ten wątek pomógł mi go rozwiązać (pierwsza odpowiedź wyjaśnia wszystko).

ALE bardzo ważne jest, aby wiedzieć, jakie są możliwe przyczyny, które mogą to powodować.

W moim przypadku tworzyłem tabelę z polem takim jak to:

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

Dlatego pole „Okres” miało długość zero i powodowało niepowodzenie operacji wstawiania. Zmieniłem go na „XXXXXX”, czyli długość przychodzących danych, i teraz działało to poprawnie (ponieważ pole miało teraz długość 6).

Mam nadzieję, że pomoże to każdemu, kto ma ten sam problem :)

RaRdEvA
źródło
7

Inną sytuacją, w której można uzyskać ten błąd, jest:

Miałem ten sam błąd, a przyczyną było to, że w instrukcji INSERT, która otrzymywała dane z UNII, kolejność kolumn była inna niż w oryginalnej tabeli. Jeśli zmienisz kolejność w # table3 na a, b, c, naprawisz błąd.

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

insert into #table1
    select a, b, c from #table2
    union
    select a, c, b from #table3
hola77
źródło
7

na serwerze sql możesz użyć SET ANSI_WARNINGS OFF w następujący sposób:

        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();

        }
Esperento57
źródło
7

Miałem ten sam problem. Długość mojego kolumny był zbyt krótki.

Możesz zwiększyć długość lub skrócić tekst, który chcesz umieścić w bazie danych.

bizimunda
źródło
7

Ten problem występował również na powierzchni aplikacji sieci web. W końcu okazało się, że ten sam komunikat o błędzie pochodzi z instrukcji aktualizacji SQL w określonej tabeli.

Wreszcie ustalono, że definicja kolumny w powiązanych tabelach historii nie odwzorowała oryginalnej długości kolumn nvarchartypów tabeli w niektórych szczególnych przypadkach.

webMac
źródło
4

Miałem ten sam problem, nawet po zwiększeniu rozmiaru problematycznych kolumn w tabeli.

tl; dr: Długość pasujących kolumn w odpowiednich typach tabel może również wymagać zwiększenia.

W moim przypadku błąd pochodził z usługi eksportu danych w Microsoft Dynamics CRM, która pozwala na synchronizację danych CRM z bazą danych SQL Server lub Azure SQL DB.

Po długim dochodzeniu doszedłem do wniosku, że usługa eksportu danych musi używać parametrów wycenionych w tabeli :

Za pomocą parametrów o wartościach przechowywanych w tabeli można wysyłać wiele wierszy danych do instrukcji Transact-SQL lub procedury, takiej jak procedura składowana lub funkcja, bez tworzenia tabeli tymczasowej lub wielu parametrów.

Jak widać w powyższej dokumentacji, typy tabel są używane do tworzenia procedury przetwarzania danych:

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

Niestety nie ma sposobu na zmianę typu tabeli, więc należy go całkowicie usunąć i odtworzyć. Ponieważ moja tabela ma ponad 300 pól (😱), utworzyłem zapytanie, aby ułatwić utworzenie odpowiedniego typu tabeli na podstawie definicji kolumn tabeli (wystarczy zastąpić [table_name]nazwą tabeli):

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;

Po zaktualizowaniu typu tabeli usługa eksportu danych znów zaczęła działać poprawnie! :)

Marco Roy
źródło
2

Podczas próby wykonania procedury składowanej miałem ten sam problem, ponieważ rozmiar kolumny, którą muszę dodać, jest mniejszy niż danych, które chcę dodać.

Możesz zwiększyć rozmiar typu danych kolumny lub skrócić długość danych.

Chamila Maddumage
źródło
1

Inną sytuacją, w której może wystąpić ten błąd, jest SQL Server Management Studio. Jeśli masz w tabeli pola „tekst” lub „ntext”, bez względu na to, jakie pole aktualizujesz (na przykład bit lub liczba całkowita). Wydaje się, że Studio nie ładuje całych pól „ntext”, a także aktualizuje WSZYSTKIE pola zamiast zmodyfikowanego. Aby rozwiązać problem, wyklucz pola „tekst” lub „ntext” z zapytania w Management Studio

Sevast
źródło
1
Rozważ sformułowanie swojej odpowiedzi, dodając przecinki, kropki i naprawiając błędy gramatyczne.
George Pamfilis,
Ta odpowiedź pomogła mi - moje pola nvarchar są wystarczająco duże, ale mam pole ntext. Wygląda na jakiś błąd w Management Studio / SMSS.
Sha
0

Potrzebowałem komentarza Kevina Pope'a pod przyjętą odpowiedzią.

Problem w moim przypadku polegał na tym, że w mojej tabeli zdefiniowane zostały wyzwalacze, które wstawiałyby aktualizacje / wstawianie transakcji do tabeli kontroli, ale tabela kontroli miała niezgodność typu danych, w której kolumna z VARCHAR(MAX)oryginalnej tabeli była przechowywana jak VARCHAR(1)w tabeli kontroli, więc moje wyzwalacze zawiodły, gdy wstawiłem coś większego niż VARCHAR(1)w oryginalnej kolumnie tabeli i otrzymałem ten komunikat o błędzie.

Sibs
źródło
0

Użyłem innej taktyki, pól, które w niektórych miejscach mają przypisane 8K. Tutaj używa się tylko około 50/100.

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

Chciałem prędkości, ponieważ mam 1M rekordów i załaduję 28K z nich.

Hans Schulze
źródło