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

250

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 existe 8 autres lignes similaires pour ajouter des enregistrements.

Quand je lance cela avec start> run> cmd> c:\data.bat, je reçois ce message d'erreur:

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>

Aussi, je suis un débutant évidemment, mais qu'est-ce que Level #, et state #signifie, et comment puis-je rechercher des messages d'erreur comme celui ci - dessus: 8152?

karthik
la source

Réponses:

609

De la réponse de @ gmmastros

Chaque fois que vous voyez le message ....

Chaîne ou des données binaires seront tronquées

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 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 mettre 11 caractères, vous obtiendrez cette erreur.

karthik
la source
16
Notez également que les champs impactés peuvent être dans un déclencheur. J'espère que je m'en souviendrai la prochaine fois que cela arrivera ...
Kevin Pope
14
Existe-t-il un moyen de voir dans le débogage quel champ serait tronqué?
DailyFrankPeter du
Cette erreur est due au fait que votre colonne ne peut pas contenir de données après la longueur que vous avez fixée. Par exemple; Firstname nvarchar(5) Si vous insérez plus de 5 caractères, vous obtiendrez l'erreur
Prakash
26

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 la piste d'audit), remplie par un déclencheur sur la table principale, où la taille de la colonne devait également être modifiée.

alterfox
la source
1
Merci. Le mien était parce que la colonne sql dans tableA est varchar (100). Il insère également dans une autre table, dans laquelle, la colonne est varchar (50).
Hnin Htet Htet Aung
1
Le même problème s'est également produit dans mon cas. Une opération de déclenchement était le coupable.
pilote automatique
19

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

S'il n'est pas évident de savoir qui INSERTest l'auteur de l'infraction par un simple examen du script, vous pouvez compter les <1 row affected>lignes qui se produisent avant le message d'erreur. Le nombre 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.

Andriy M
la source
2
J'ai le même problème, comment trouver la colonne à l'origine de l'erreur?
Cátia Matos
@ AndréBastos: Peut-être pourriez-vous soumettre cela comme une question (à moins que quelqu'un d'autre ne l'ait déjà fait, auquel cas il peut y avoir une réponse prête quelque part).
Andriy M
11

Certaines de vos données ne peuvent pas entrer dans votre colonne de base de données (petite). Il 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é:

Créez d'abord 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);
                    }

                }
            }
        }
    }
}

Préparez ensuite 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'exceptions global et les détails de troncature 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();
Tomas Kubes
la source
9

Je veux juste contribuer avec des informations supplémentaires: j'ai eu 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 du haut 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 provoquait l'échec des opérations d'insertion. Je l'ai changé 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 toute personne ayant le même problème :)

RaRdEvA
la source
7

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

J'ai eu la même erreur et la raison en est que dans une instruction INSERT qui a reçu des données d'un UNION, l'ordre des colonnes était différent de la table d'origine. Si vous changez 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
hola77
la source
7

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

        }
Esperento57
la source
7

J'ai eu le même problème. La longueur de ma chronique était trop courte.

Vous pouvez soit augmenter la longueur, soit raccourcir le texte que vous souhaitez mettre dans la base de données.

bizimunda
la source
7

Ce problème s'est également produit sur la surface de l'application Web. Finalement découvert que le même message d'erreur provient de l'instruction de mise à jour SQL dans le tableau spécifique.

Enfin, nous avons compris que la définition de colonne dans les tables d'historique correspondantes ne correspondait pas à la longueur de colonne de table d'origine des nvarchartypes dans certains cas spécifiques.

webMac
la source
4

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

tl; dr: La longueur des colonnes correspondantes dans les types de tableaux correspondants peut également devoir être augmentée.

Dans mon cas, l'erreur provenait du service d'exportation de données dans Microsoft Dynamics CRM, qui permet aux données CRM d'être synchronisées avec une base de données SQL Server ou Azure SQL DB.

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

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

Comme vous pouvez le voir 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'y a aucun moyen de modifier un type de table, il doit donc être supprimé et recréé entièrement. Étant donné que ma table contient 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 la 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 avoir mis à jour le type de table, le service d'exportation de données a recommencé à fonctionner correctement! :)

Marco Roy
la source
2

Lorsque 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 plus courte que les données que je veux ajouter.

Vous pouvez augmenter la taille du type de données de colonne ou réduire la longueur de vos données.

Chamila Maddumage
la source
1

Une autre situation, dans laquelle cette erreur peut se produire, se trouve dans 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). Il semble que le Studio ne charge pas les champs "ntext" entiers et met également à jour TOUS les champs au lieu du champ modifié. Pour résoudre le problème, excluez les champs "texte" ou "ntext" de la requête dans Management Studio

Sevast
la source
1
Veuillez envisager de reformuler votre réponse en ajoutant des virgules, des points et en corrigeant vos erreurs de grammaire.
George Pamfilis
Cette réponse m'a aidé - mes champs nvarchar sont assez grands mais j'ai un champ ntext. Semble être une erreur dans Management Studio / SMSS.
Sha
0

Le commentaire de Kevin Pope sous la réponse acceptée était ce dont j'avais besoin.

Le problème, dans mon cas, était que j'avais défini des déclencheurs sur ma table qui inséraient des transactions de mise à jour / insertion dans une table d'audit, mais la table d'audit avait une incompatibilité de type de données où une colonne avec VARCHAR(MAX)dans la table d'origine était stockée comme VARCHAR(1)dans le table d'audit, donc mes déclencheurs échouaient lorsque j'insérais quelque chose de plus grand que VARCHAR(1)dans la colonne de table d'origine et j'obtenais ce message d'erreur.

Sibs
la source
0

J'ai utilisé une tactique différente, des champs qui sont alloués 8K à certains endroits. Ici, seuls 50/100 environ sont utilisés.

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

Je voulais de la vitesse, car j'ai 1M d'enregistrements au total et j'en charge 28K.

Hans Schulze
la source