error, cadena o datos binarios se truncarían al intentar insertar

250

Estoy ejecutando el archivo data.bat con las siguientes líneas:

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

El contenido del archivo data.sql es:

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

Hay 8 líneas más similares para agregar registros.

Cuando ejecuto esto con start> run> cmd> c:\data.bat, me sale este mensaje de error:

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>

Además, obviamente soy un novato, pero ¿qué hago Level #y qué quiero state #decir, y cómo busco mensajes de error como el anterior: 8152?

karthik
fuente

Respuestas:

609

De la respuesta de @ gmmastros

Cada vez que ves el mensaje ...

Cadena o datos binarios podrían truncarse

Piensa para ti mismo ... El campo NO es lo suficientemente grande como para contener mis datos.

Verifique la estructura de la tabla para la tabla de clientes. Creo que descubrirá que la longitud de uno o más campos NO es lo suficientemente grande como para contener los datos que está tratando de insertar. Por ejemplo, si el campo Teléfono es un campo varchar (8) e intenta colocar 11 caracteres, obtendrá este error.

karthik
fuente
16
También tenga en cuenta que los campos afectados podrían estar en un disparador. Espero recordar esto la próxima vez que esto suceda ...
Kevin Pope
14
¿Hay alguna forma de ver en la depuración qué campo se truncaría?
DailyFrankPeter
Este error se debe a que su columna no puede contener datos después de la longitud que arregló. P.ej; Firstname nvarchar(5) Si inserta más de 5 caracteres obtendrá el error
Prakash
26

Tuve este problema, aunque la longitud de los datos fue más corta que la longitud del campo. Resultó que el problema era tener otra tabla de registro (para el seguimiento de auditoría), llena por un disparador en la tabla principal, donde el tamaño de la columna también tenía que cambiarse.

alterfox
fuente
1
Gracias. El mío fue porque la columna sql en la tabla A es varchar (100). También se inserta en otra tabla, en la cual, la columna es varchar (50).
Hnin Htet Htet Aung
1
El mismo problema ocurrió en mi caso también. Una operación desencadenante fue el culpable.
piloto automático
19

En una de las INSERTdeclaraciones, está intentando insertar una cadena demasiado larga en una columna de cadena ( varcharo nvarchar).

Si no es obvio cuál INSERTes el infractor con solo mirar el script, puede contar las <1 row affected>líneas que aparecen antes del mensaje de error. El número obtenido más uno le da el número de extracto. En su caso, parece ser el segundo INSERT que produce el error.

Andriy M
fuente
2
Tengo el mismo problema, ¿cómo encontrar qué columna está causando el error?
Cátia Matos
@ AndréBastos: Quizás podría enviarlo como una pregunta (a menos que otra persona ya lo haya hecho, en cuyo caso puede haber una respuesta lista en algún lugar).
Andriy M
11

Algunos de sus datos no pueden caber en la columna de su base de datos (pequeña). No es fácil encontrar lo que está mal. Si usa C # y Linq2Sql, puede enumerar el campo que se truncaría:

Primero cree la clase auxiliar:

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

                }
            }
        }
    }
}

Luego prepare el contenedor para 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;
        }
    }
}

Prepare el controlador de excepción global y los detalles de truncamiento del registro:

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

Finalmente usa el código:

Datamodel.SubmitChangesWithDetailException();
Tomás Kubes
fuente
9

Solo quiero contribuir con información adicional: tuve el mismo problema y fue porque el campo no era lo suficientemente grande para los datos entrantes y este hilo me ayudó a resolverlo (la respuesta principal lo aclara todo).

PERO es muy importante saber cuáles son las posibles razones que pueden causarlo.

En mi caso, estaba creando la tabla con un campo como este:

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

Por lo tanto, el campo "Período" tenía una longitud de cero y hacía que las operaciones de inserción fallaran. Lo cambié a "XXXXXX", que es la longitud de los datos entrantes y ahora funcionaba correctamente (porque el campo ahora tenía una longitud de 6).

Espero que esto ayude a cualquiera con el mismo problema :)

RADIO
fuente
7

Otra situación en la que puede obtener este error es la siguiente:

Tuve el mismo error y la razón fue que en una declaración INSERT que recibió datos de una UNIÓN, el orden de las columnas era diferente de la tabla original. Si cambia el orden en # table3 a a, b, c, solucionará el error.

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
fuente
7

en el servidor sql puede usar SET ANSI_WARNINGS OFF así:

        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
fuente
7

Tuve el mismo problema. La longitud de mi columna era demasiado corta.

Lo que puede hacer es aumentar la longitud o acortar el texto que desea poner en la base de datos.

bizimunda
fuente
7

También tuve este problema en la superficie de la aplicación web. Eventualmente descubrí que el mismo mensaje de error proviene de la declaración de actualización de SQL en la tabla específica.

Finalmente, descubrí que la definición de columna en la (s) tabla (s) histórica (s) correspondiente (s) no mapeó la longitud de los nvarchartipos de columna de la tabla original en algunos casos específicos.

webMac
fuente
4

Tuve el mismo problema, incluso después de aumentar el tamaño de las columnas problemáticas en la tabla.

tl; dr: la longitud de las columnas coincidentes en los tipos de tabla correspondientes también puede necesitar ser aumentada.

En mi caso, el error provenía del servicio de exportación de datos en Microsoft Dynamics CRM, que permite que los datos de CRM se sincronicen con una base de datos SQL Server o Azure SQL DB.

Después de una larga investigación, llegué a la conclusión de que el servicio de exportación de datos debe estar utilizando parámetros con valores de tabla :

Puede usar parámetros con valores de tabla para enviar varias filas de datos a una instrucción Transact-SQL o una rutina, como un procedimiento almacenado o una función, sin crear una tabla temporal o muchos parámetros.

Como puede ver en la documentación anterior, los Tipos de tabla se utilizan para crear el procedimiento de ingestión de datos:

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

Desafortunadamente, no hay forma de alterar un tipo de tabla, por lo que debe descartarse y recrearse por completo. Como mi tabla tiene más de 300 campos (😱), creé una consulta para facilitar la creación del Tipo de tabla correspondiente en función de la definición de las columnas de la tabla (solo reemplace [table_name]con el nombre de su tabla):

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;

Después de actualizar el Tipo de tabla, el servicio de exportación de datos comenzó a funcionar correctamente una vez más. :)

Marco Roy
fuente
2

Cuando intenté ejecutar mi procedimiento almacenado, tuve el mismo problema porque el tamaño de la columna que necesito para agregar algunos datos es más corto que los datos que quiero agregar.

Puede aumentar el tamaño del tipo de datos de la columna o reducir la longitud de sus datos.

Chamila Maddumage
fuente
1

Otra situación en la que puede ocurrir este error es en SQL Server Management Studio. Si tiene campos de "texto" o "ntext" en su tabla, no importa qué tipo de campo esté actualizando (por ejemplo, bit o entero). Parece que Studio no carga todos los campos "ntext" y también actualiza TODOS los campos en lugar del campo modificado. Para resolver el problema, excluya los campos "texto" o "ntext" de la consulta en Management Studio

Sevast
fuente
1
Considere reformular su respuesta agregando comas, puntos y corrigiendo sus errores gramaticales.
George Pamfilis
Esta respuesta me ayudó: mis campos nvarchar son lo suficientemente grandes pero tengo un campo ntext. Parece haber algún error en Management Studio / SMSS.
Sha
0

Kevin Pope's comentario de bajo la respuesta aceptada fue lo que necesitaba.

El problema, en mi caso, era que tenía desencadenantes definidos en mi tabla que insertarían transacciones de actualización / inserción en una tabla de auditoría, pero la tabla de auditoría tenía un desajuste de tipo de datos donde una columna con VARCHAR(MAX)en la tabla original se almacenaba como VARCHAR(1)en el auditoría de la tabla, por lo que mis desencadenadores fallaban cuando insertaba algo mayor que VARCHAR(1)en la columna de la tabla original y recibía este mensaje de error.

Sibs
fuente
0

Utilicé una táctica diferente, campos que se asignan 8K en algunos lugares. Aquí solo se usan aproximadamente 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

Quería velocidad, ya que tengo 1M de registros totales, y cargo 28K de ellos.

Hans Schulze
fuente