i dati di errore, stringa o binari verrebbero troncati quando si tenta di inserire


250

Sto eseguendo il file data.bat con le seguenti righe:

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

Il contenuto del file data.sql è:

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

Ci sono altre 8 righe simili per l'aggiunta di record.

Quando eseguo questo con start> run> cmd> c:\data.bat, ottengo questo messaggio di errore:

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>

Inoltre, sono un principiante ovviamente, ma cosa significano Level #e cosa state #significano e come posso cercare messaggi di errore come quello sopra: 8152?

Risposte:


609

Dalla risposta di @ gmmastros

Ogni volta che vedi il messaggio ....

i dati stringa o binari verrebbero troncati

Pensa a te stesso ... Il campo NON è abbastanza grande per contenere i miei dati.

Controllare la struttura della tabella per la tabella dei clienti. Penso che scoprirai che la lunghezza di uno o più campi NON è abbastanza grande da contenere i dati che stai cercando di inserire. Ad esempio, se il campo Telefono è un campo varchar (8) e si tenta di inserire 11 caratteri, verrà visualizzato questo errore.


16
Si noti inoltre che i campi interessati potrebbero essere in un trigger. Spero di ricordarmelo la prossima volta che succederà ...
Kevin Pope,

14
Esiste un modo per vedere nel debug quale campo verrebbe troncato?
DailyFrankPeter

Questo errore è dovuto al fatto che la colonna non può contenere dati dopo la lunghezza fissata. Per esempio; Firstname nvarchar(5) Se inserisci più di 5 caratteri otterrai l'errore
Prakash

26

Ho avuto questo problema, sebbene la lunghezza dei dati fosse inferiore alla lunghezza del campo. Si è scoperto che il problema stava avendo un'altra tabella di registro (per audit trail), riempita da un trigger sulla tabella principale, dove anche le dimensioni della colonna dovevano essere modificate.


1
Grazie. Il mio era perché la colonna sql nella tabella A è varchar (100). Si inserisce anche in un'altra tabella, in cui la colonna è varchar (50).
Hnin Htet Htet Aung,

1
Lo stesso problema si è verificato anche nel mio caso. Il colpevole era un'operazione di innesco.
pilota automatico

19

In una delle INSERTistruzioni si sta tentando di inserire una stringa troppo lunga in una colonna stringa ( varcharo nvarchar).

Se non è ovvio quale INSERTsia l'autore del reato da un semplice sguardo allo script, è possibile contare le <1 row affected>righe che si verificano prima del messaggio di errore. Il numero ottenuto più uno ti dà il numero di estratto conto. Nel tuo caso sembra essere il secondo INSERTO che produce l'errore.


2
Sto riscontrando lo stesso problema, come trovare quale colonna causa l'errore?
Cátia Matos,

@ AndréBastos: forse potresti inviarlo come una domanda (a meno che qualcun altro non l'abbia già fatto, nel qual caso potrebbe esserci una risposta pronta da qualche parte).
Andriy M,

11

Alcuni dei tuoi dati non possono rientrare nella colonna del tuo database (piccola). Non è facile trovare ciò che è sbagliato. Se usi C # e Linq2Sql, puoi elencare il campo che verrebbe troncato:

Per prima cosa crea una classe di supporto:

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

                }
            }
        }
    }
}

Quindi preparare il wrapper per SubmitChanges:

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

Preparare i dettagli del troncamento del gestore delle eccezioni globale e del registro:

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

Infine usa il codice:

Datamodel.SubmitChangesWithDetailException();

9

Voglio solo contribuire con ulteriori informazioni: ho avuto lo stesso problema ed era a causa del fatto che il campo non era abbastanza grande per i dati in arrivo e questo thread mi ha aiutato a risolverlo (la risposta in alto chiarisce tutto).

MA è molto importante sapere quali sono le possibili ragioni che possono causarlo.

Nel mio caso stavo creando la tabella con un campo come questo:

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

Pertanto, il campo "Periodo" aveva una lunghezza pari a zero e causava il fallimento delle operazioni di inserimento. L'ho cambiato in "XXXXXX" che è la lunghezza dei dati in arrivo e ora funzionava correttamente (perché il campo ora aveva una lunghezza di 6).

Spero che questo aiuti chiunque abbia lo stesso problema :)


7

Un'altra situazione in cui è possibile ottenere questo errore è la seguente:

Ho avuto lo stesso errore e il motivo era che in un'istruzione INSERT che riceveva dati da un UNION, l'ordine delle colonne era diverso dalla tabella originale. Se cambi l'ordine in # table3 in a, b, c, correggerai l'errore.

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

su SQL Server è possibile utilizzare SET ANSI_WARNINGS OFF in questo modo:

        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

Ho avuto lo stesso problema. La lunghezza della mia colonna era troppo corta.

Quello che puoi fare è aumentare la lunghezza o accorciare il testo che vuoi inserire nel database.


7

Inoltre, si è verificato questo problema sulla superficie dell'applicazione Web. Alla fine ho scoperto che lo stesso messaggio di errore proviene dall'istruzione di aggiornamento SQL nella tabella specifica.

Infine, ho capito che la definizione della colonna nelle tabelle della cronologia relativa non mappava la lunghezza dei nvarchartipi della colonna della tabella originale in alcuni casi specifici.


4

Ho avuto lo stesso problema, anche dopo aver aumentato le dimensioni delle colonne problematiche nella tabella.

tl; dr: potrebbe essere necessario aumentare anche la lunghezza delle colonne corrispondenti nei tipi di tabella corrispondenti.

Nel mio caso, l'errore proveniva dal servizio di esportazione dei dati in Microsoft Dynamics CRM, che consente di sincronizzare i dati CRM con un DB di SQL Server o un database SQL di Azure.

Dopo una lunga indagine, ho concluso che il servizio di esportazione dei dati deve utilizzare parametri a valori di tabella :

È possibile utilizzare i parametri con valori di tabella per inviare più righe di dati a un'istruzione Transact-SQL o a una routine, ad esempio una stored procedure o una funzione, senza creare una tabella temporanea o molti parametri.

Come puoi vedere nella documentazione sopra, i tipi di tabella vengono utilizzati per creare la procedura di inserimento dati:

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

Sfortunatamente, non c'è modo di modificare un tipo di tabella, quindi deve essere eliminato e ricreato del tutto. Poiché la mia tabella ha oltre 300 campi (😱), ho creato una query per facilitare la creazione del tipo di tabella corrispondente in base alla definizione delle colonne della tabella (basta sostituire [table_name]con il nome della tabella):

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;

Dopo aver aggiornato il tipo di tabella, il servizio di esportazione dei dati ha ripreso a funzionare correttamente! :)


2

Quando ho provato a eseguire la procedura memorizzata, ho riscontrato lo stesso problema perché la dimensione della colonna di cui ho bisogno per aggiungere alcuni dati è più corta dei dati che voglio aggiungere.

È possibile aumentare le dimensioni del tipo di dati della colonna o ridurre la lunghezza dei dati.


1

Un'altra situazione, in cui può verificarsi questo errore, è in SQL Server Management Studio. Se nella tabella sono presenti campi "text" o "ntext", indipendentemente dal tipo di campo che si sta aggiornando (ad esempio bit o intero). Sembra che Studio non carichi interi campi "ntext" e aggiorni anche TUTTI i campi invece di quello modificato. Per risolvere il problema, escludere i campi "text" o "ntext" dalla query in Management Studio


1
Ti preghiamo di considerare di riformulare la tua risposta aggiungendo virgole, punti e correggendo gli errori grammaticali.
George Pamfilis,

Questa risposta mi ha aiutato: i miei campi nvarchar sono abbastanza grandi ma ho un campo ntext. Sembra essere un errore in Management Studio / SMSS.
Sha

0

Il commento di Kevin Pope sotto la risposta accettata era ciò di cui avevo bisogno.

Il problema, nel mio caso, era che avevo definito i trigger nella mia tabella che avrebbero inserito le transazioni di aggiornamento / inserimento in una tabella di controllo, ma la tabella di controllo aveva una mancata corrispondenza del tipo di dati in cui VARCHAR(MAX)era archiviata una colonna con nella tabella originale come VARCHAR(1)nella tabella di controllo, quindi i miei trigger non funzionavano quando avrei inserito qualcosa di più grande rispetto VARCHAR(1)alla colonna della tabella originale e avrei ricevuto questo messaggio di errore.


0

Ho usato una tattica diversa, i campi che sono assegnati 8K in alcuni punti. Qui vengono utilizzati solo circa 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

Volevo velocità, dato che ho 1 milione di record totali e ne carica 28.000.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.