web-dev-qa-db-fra.com

erreur, chaîne ou données binaires seraient tronquées lors d'une tentative d'insertion

J'exécute le fichier data.bat avec les lignes suivantes:

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

Le contenu du fichier data.sql est:

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

Il y a 8 autres lignes similaires pour l'ajout d'enregistrements.

Lorsque je lance ceci avec start> run> cmd> c:\data.bat, le message d'erreur suivant s'affiche:

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>

De plus, je suis un débutant évidemment, mais que signifient Level #, et state # et comment puis-je rechercher des messages d'erreur tels que celui ci-dessus: 8152?

206
karthik

De la réponse de @ gmmastros

Chaque fois que vous voyez le message ....

string or binary data would be truncated 

Pensez à vous-même ... Le champ n'est PAS assez grand pour contenir mes données.

Vérifiez la structure de la table pour la table des clients. Je pense que vous constaterez que la longueur d'un ou de plusieurs champs n'est PAS assez grande pour contenir les données que vous essayez d'insérer. Par exemple, si le champ Téléphone est un champ varchar (8) et que vous essayez d'y insérer 11 caractères, vous obtiendrez cette erreur. 

538
karthik

Dans l'une des instructions INSERT, vous essayez d'insérer une chaîne trop longue dans une colonne de chaîne (varchar ou nvarchar).

S'il n'est pas évident de savoir quel est le délinquant INSERT en regardant le script, vous pouvez compter les lignes <1 row affected> qui apparaissent avant le message d'erreur. Le numéro obtenu plus un vous donne le numéro du relevé. Dans votre cas, il semble que ce soit le deuxième INSERT qui génère l'erreur.

18
Andriy M

J'ai eu ce problème bien que la longueur des données soit plus courte que la longueur du champ . Il s'est avéré que le problème était d'avoir une autre table de journal (pour le journal d'audit), remplie par un déclencheur sur la table principale, où la taille de la colonne être changé.

17
alterfox

Certaines de vos données ne peuvent pas entrer dans la colonne de votre base de données (petite). Ce n'est pas facile de trouver ce qui ne va pas. Si vous utilisez C # et Linq2Sql, vous pouvez lister le champ qui serait tronqué:

Commencez par créer une classe d'assistance:

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

                }
            }
        }
    }
}

Ensuite, préparez le wrapper pour 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;
        }
    }
}

Préparez le gestionnaire d'exception global et les détails de troncation du journal:

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

Enfin, utilisez le code:

Datamodel.SubmitChangesWithDetailException();
11
Tomas Kubes

Une autre situation dans laquelle vous pouvez obtenir cette erreur est la suivante:

J'ai eu la même erreur et la raison était que, dans une instruction INSERT recevant des données d'un UNION, l'ordre des colonnes était différent de celui de la table d'origine. Si vous modifiez l'ordre dans # table3 en a, b, c, vous corrigerez l'erreur.

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
hola77

Je veux juste contribuer avec des informations supplémentaires: j'avais le même problème et c'était parce que le champ n'était pas assez grand pour les données entrantes et ce fil m'a aidé à le résoudre (la réponse la plus claire clarifie tout).

MAIS il est très important de savoir quelles sont les raisons possibles qui peuvent en être la cause.

Dans mon cas, je créais la table avec un champ comme celui-ci:

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

Par conséquent, le champ "Période" avait une longueur de zéro et entraînait l'échec des opérations d'insertion. Je l'ai changée en "XXXXXX", c'est-à-dire la longueur des données entrantes et cela fonctionnait maintenant correctement (car le champ avait maintenant une longueur de 6).

J'espère que cela aidera quelqu'un avec le même problème :)

7
RaRdEvA

Ce problème se produisait également à la surface de l'application Web. Éventuellement découvert que le même message d'erreur provient de l'instruction de mise à jour SQL de la table spécifique. 

Enfin, nous avons enfin découvert que la définition de colonne dans la ou les tables d’historique correspondantes ne mappait pas la longueur de la colonne de table originale de types nvarchar dans certains cas spécifiques.  

J'espère que cet indice aide aussi quelqu'un d'autre ..;) 

7
webMac

sur serveur SQL, vous pouvez utiliser SET ANSI_WARNINGS OFF comme ceci:

        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
Esperento57

J'ai eu le même problème… .. La longueur de ma colonne était trop courte… .. Ce que vous pouvez faire est soit augmenter la longueur ou raccourcir le texte que vous voulez mettre dans la base de données.

6
user2983359

Quand j'ai essayé d'exécuter ma procédure stockée, j'ai eu le même problème car la taille de la colonne dont j'ai besoin pour ajouter des données est inférieure à celle que je veux ajouter. Vous pouvez augmenter la taille du type de données de la colonne ou réduire la longueur de vos données.

1
Chamila Maddumage

Une autre situation dans laquelle cette erreur peut survenir est celle de SQL Server Management Studio. Si vous avez des champs "texte" ou "ntext" dans votre table, Quel que soit le type de champ que vous mettez à jour (par exemple, bit ou entier) . et met également à jour TOUS les champs au lieu du champ modifié . Pour résoudre le problème, excluez les champs "text" ou "ntext" de la requête dans Management Studio.

1
Sevast

J'ai eu le même problème, même après avoir augmenté la taille des colonnes problématiques du tableau.

tl; dr: il peut également être nécessaire d'augmenter la longueur des colonnes correspondantes des types de table correspondants.

Dans mon cas, l'erreur provenait du service d'exportation de données de Microsoft Dynamics CRM, qui permet la synchronisation des données CRM vers une base de données SQL Server ou Azure SQL.

Après une longue enquête, j'ai conclu que le service d'exportation de données devait utiliser Paramètres à valeur de table :

Vous pouvez utiliser des paramètres table pour envoyer plusieurs lignes de données à une instruction ou à une routine Transact-SQL, telle qu'une procédure ou une fonction stockée, sans créer de table temporaire ni de nombreux paramètres.

Comme vous pouvez le constater dans la documentation ci-dessus, les types de table sont utilisés pour créer la procédure d'ingestion de données:

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

Malheureusement, il n’ya aucun moyen de modifier un type de table, il doit donc être supprimé et recréé entièrement. Comme ma table a plus de 300 champs (????), j'ai créé une requête pour faciliter la création du type de table correspondant en fonction de la définition des colonnes de la table (il suffit de remplacer [table_name] par le nom de votre table):

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;

Après la mise à jour du type de table, le service d'exportation de données a de nouveau fonctionné correctement! :)

0
Marco Roy