Cadena de SQL Server o datos binarios se truncarían

149

Estoy involucrado en un proyecto de migración de datos. Recibo el siguiente error cuando intento insertar datos de una tabla en otra tabla (SQL Server 2005):

El mensaje 8152, Nivel 16, Estado 13, Línea 1
Cadena o datos binarios se truncarían.

Las columnas de datos de origen coinciden con el tipo de datos y están dentro de las definiciones de longitud de las columnas de la tabla de destino, por lo que no sé qué podría estar causando este error.

Jim Evans
fuente
¿Te importaría publicar algún código e información sobre cada tabla?
Kevin Mansel
Las tablas son bastante grandes, por lo que publicaré solo la parte de las definiciones de tabla que están involucradas y el código, ¿es eso aceptable?
Jim Evans
Las definiciones de la tabla y el código serían geniales.
IAmTimCorey
1
La última vez que tuve este problema, fue con el disparador, el disparador estaba insertando datos en una tabla de auditoría. Vale la pena comprobar el gatillo también.
Sachin Vishwakarma

Respuestas:

185

Tendrá que publicar las definiciones de tabla para las tablas de origen y destino para que podamos determinar dónde está el problema, pero la conclusión es que una de sus columnas en la tabla de origen es más grande que sus columnas de destino . Puede ser que esté cambiando formatos de una manera que no conocía. El modelo de base de datos del que se está mudando también es importante para descubrirlo.

IAmTimCorey
fuente
1
Por mi comentario anterior - próximamente :)
Jim Evans
3
Me enfrenté al mismo problema y tuve que comparar todos los tipos y tamaños de columna de ambas tablas para solucionar el problema.
Aziz Shaikh
1
Después de pasar el ejercicio de reunir las definiciones parciales de la tabla y luego obtener mi código sproc, la columna ofensiva saltó hacia mí como un rayo ... Gracias a todos por su aporte.
Jim Evans
No puedo decirte cuántas veces he hecho lo mismo. Me alegra que hayas podido resolver tu problema.
IAmTimCorey
Marqué su primera respuesta como la respuesta porque fue lo que me llevó a encontrar la respuesta :)
Jim Evans
86

Como ya han dicho otros, uno de los tipos de datos de sus columnas en la tabla de origen es más grande que sus columnas de destino.

Una solución simple es simplemente apagar la advertencia y permitir que se produzca el truncamiento. Por lo tanto, si recibe este error pero está seguro de que es aceptable que los datos de su antigua base de datos / tabla se trunquen (corten a tamaño), simplemente puede hacer lo siguiente;

SET ANSI_WARNINGS  OFF;
-- Your insert TSQL here.
SET ANSI_WARNINGS ON;

Como se indicó anteriormente, recuerde siempre volver a activar las advertencias después. Espero que esto ayude.

Rudi Kershaw
fuente
1
¡Me salvaste algunas horas de trabajo! ¡Toma todas mis gracias!
Urasquirrel
Del mismo modo aquí. A veces tengo que almacenar datos en una tabla desde, por ejemplo, un servicio web, donde el tipo de datos se define solo como una "cadena". No puedo hacer que todo sea un Varchar (MAX) ...
Curt
61

El problema es bastante simple: una o más de las columnas en la consulta de origen contienen datos que exceden la longitud de su columna de destino. Una solución simple sería tomar su consulta de origen y ejecutarla Max(Len( source col ))en cada columna. Es decir,

Select Max(Len(TextCol1))
    , Max(Len(TextCol2))
    , Max(Len(TextCol3))
    , ...
From ...

Luego compare esas longitudes con las longitudes de tipo de datos en su tabla de destino. Al menos uno, excede la longitud de su columna de destino.

Si está absolutamente seguro de que este no debería ser el caso y no le importa si no es el caso , entonces otra solución es convertir a la fuerza las columnas de consulta de origen a su longitud de destino (lo que truncará cualquier dato que sea demasiado largo):

Select Cast(TextCol1 As varchar(...))
    , Cast(TextCol2 As varchar(...))
    , Cast(TextCol3 As varchar(...))
    , ...
From ...
Thomas
fuente
Mi proceso diario comenzó a romperse con este error. Los datos que inserto siempre fueron lo suficientemente cortos como para caber y siempre tuve otras filas (en la tabla que estaba extrayendo) con cadenas de gran tamaño que nunca se insertaron debido a mi filtro. Tal vez se reconstruyó un índice o se actualizaron las estadísticas, pero el fantasma en la máquina decidió un día que ya no le gustaba el plan de consulta, porque lo llevó por un camino donde los datos (que eran demasiado amplios) "podrían" estar insertado antes de que fuera filtrado por el predicado en la cláusula Where. Para evitar esto, utilicé LEFT () en lugar de CAST, solo que menos caracteres para escribir.
MikeTeeVee
1
Gracias Thomas, esto es extraño, incluso si no tengo ningún dato que sea demasiado largo, aún tengo que convertirlo al nuevo tamaño de columna de destino, tan pronto como lo hice, funcionó.
Michelle
15

SQL Server 2019 finalmente devolverá un mensaje de error más significativo.

Los datos binarios o de cadena se truncarían => mejoras de mensajes de error

Si tiene ese error (en producción), no es obvio ver de qué columna o fila proviene este error y cómo ubicarlo exactamente.

Para habilitar un nuevo comportamiento, debe usarlo DBCC TRACEON(460). Nuevo texto de error de sys.messages:

SELECT * FROM sys.messages WHERE message_id = 2628

2628 - Los datos de cadena o binarios se truncarían en la tabla '%. * Ls', columna '%. * Ls'. Valor truncado: '%. * Ls'.

Los datos de cadena o binarios se truncarían: reemplazando el infame error 8152

Este nuevo mensaje también es compatible con SQL Server 2017 CU12 (y en un próximo SQL Server 2016 SP2 CU), pero no de manera predeterminada. Debe habilitar el indicador de seguimiento 460 para reemplazar el ID de mensaje 8152 con 2628, ya sea a nivel de sesión o de servidor.

Tenga en cuenta que, por ahora, incluso en SQL Server 2019 CTP 2.0, se debe habilitar el mismo indicador de seguimiento 460. En una futura versión de SQL Server 2019, el mensaje 2628 reemplazará al mensaje 8152 de manera predeterminada.


SQL Server 2017 CU12 también es compatible con esta característica.

Mejora: Reemplazo opcional para el mensaje "La cadena o los datos binarios se truncarían" con información extendida en SQL Server 2017

Esta actualización de SQL Server 2017 presenta un mensaje opcional que contiene la siguiente información de contexto adicional.

Msg 2628, Level 16, State 6, Procedure ProcedureName, Line Linenumber
String or binary data would be truncated in table '%.*ls', column '%.*ls'.
Truncated value: '%.*ls'.

El nuevo ID de mensaje es 2628. Este mensaje reemplaza el mensaje 8152 en cualquier salida de error si la marca de seguimiento 460 está habilitada.

db <> demostración de violín


ALTERAR BASE DE DATOS CONFIGURACIÓN ALCANZADA

VERBOSE_TRUNCATION_WARNINGS = {ON | APAGADO }

SE APLICA A: SQL Server (a partir de SQL Server 2019 (15.x)) y Azure SQL Database

Le permite habilitar o deshabilitar la nueva cadena o los datos binarios se truncarían mensaje de error. SQL Server 2019 (15.x) presenta un nuevo mensaje de error más específico (2628) para este escenario:

String or binary data would be truncated in table '%.*ls', column'%.*ls'. Truncated value: '%.*ls'.

Cuando se establece en ON bajo el nivel de compatibilidad de la base de datos 150, los errores de truncamiento generan el nuevo mensaje de error 2628 para proporcionar más contexto y simplificar el proceso de solución de problemas.

Cuando se establece en OFF bajo el nivel de compatibilidad de la base de datos 150, los errores de truncamiento generan el mensaje de error anterior 8152.

Para el nivel de compatibilidad de la base de datos 140 o inferior, el mensaje de error 2628 sigue siendo un mensaje de error de aceptación que requiere que se habilite el indicador de seguimiento 460, y esta configuración del alcance de la base de datos no tiene ningún efecto.

Lukasz Szozda
fuente
1
Ahora también está disponible para SQL Azure: azure.microsoft.com/en-gb/updates/…
Ian Kemp
7

Otra razón potencial para esto es si tiene una configuración de valor predeterminada para una columna que excede la longitud de la columna. Parece que alguien gordo toqueteó una columna que tenía una longitud de 5 pero el valor predeterminado excedía la longitud de 5. Esto me volvió loco ya que estaba tratando de entender por qué no funcionaba en ningún inserto, incluso si todo lo que estaba insertando era una sola columna con un entero de 1. Debido a que el valor predeterminado en el esquema de la tabla tenía ese valor predeterminado que violaba, lo estropeó todo, lo que supongo que nos lleva a la lección aprendida, evite tener tablas con valores predeterminados en el esquema. :)

Brian
fuente
1
No creo que evitar los valores predeterminados sea una buena solución. Los valores predeterminados son muy útiles. No resolvería los "problemas" de la base de datos causados ​​por errores tipográficos al eliminar los valores predeterminados ...
Jacob H
3

Para los demás, también verifique su procedimiento almacenado . En mi caso, en mi procedimiento almacenado, CustomSearchaccidentalmente declaró que no tenía la longitud suficiente para mi columna, por lo que cuando ingresé una gran cantidad de datos recibí ese error, aunque tengo una gran longitud en mi base de datos. Acabo de cambiar la longitud de mi columna en mi búsqueda personalizada, el error desaparece. Esto es solo para el recordatorio. Gracias.

larva del moscardón
fuente
Esto es exactamente lo que me pasa. las tablas de origen / destino coinciden bien, pero el proceso almacenado tenía una #table definida con una longitud más corta y falló allí. ¡Gracias!
Joy Walker
3

Esto puede ser un error desafiante. Aquí hay algunas notas tomadas de https://connect.microsoft.com/SQLServer/feedback/details/339410/ busque el comentario de AmirCharania.

Ajusté la respuesta dada por AmirCharania para los datos seleccionados en una tabla real, en lugar de una temporal. Primero seleccione su conjunto de datos en una tabla de desarrollo y luego ejecute lo siguiente:

WITH CTE_Dev
AS (
    SELECT C.column_id
        ,ColumnName = C.NAME
        ,C.max_length
        ,C.user_type_id
        ,C.precision
        ,C.scale
        ,DataTypeName = T.NAME
    FROM sys.columns C
    INNER JOIN sys.types T ON T.user_type_id = C.user_type_id
    WHERE OBJECT_ID = OBJECT_ID('YOUR TARGET TABLE NAME HERE, WITH SCHEMA')
    )
    ,CTE_Temp
AS (
    SELECT C.column_id
        ,ColumnName = C.NAME
        ,C.max_length
        ,C.user_type_id
        ,C.precision
        ,C.scale
        ,DataTypeName = T.NAME
    FROM sys.columns C
    INNER JOIN sys.types T ON T.user_type_id = C.user_type_id
    WHERE OBJECT_ID = OBJECT_ID('YOUR TEMP TABLE NAME HERE, WITH SCHEMA')
    )
SELECT *
FROM CTE_Dev D
FULL OUTER JOIN CTE_Temp T ON D.ColumnName = T.ColumnName
WHERE ISNULL(D.max_length, 0) < ISNULL(T.max_length, 999)
Mcfea
fuente
Parece que MS ha cerrado el sitio de Connect. El nuevo enlace a este problema es: feedback.azure.com/forums/908035-sql-server/suggestions/… ... todavía marcado como no planificado. Creo que el comentario al que te refieres se truncó (irónicamente) cuando ocurrió la migración.
SWalters - Restablecer Monica
Curiosamente, el problema se abrió nuevamente con un título ligeramente diferente: feedback.azure.com/forums/908035-sql-server/suggestions/… y se ha enumerado como "En revisión", por lo que todavía hay esperanza.
SWalters - Restablecer Monica
3

Aquí hay una respuesta ligeramente diferente. Es posible que todos los nombres y longitudes de las columnas coincidan, pero quizás esté especificando las columnas en el orden incorrecto en su instrucción SELECT. Digamos que tableX y tableY tienen columnas con el mismo nombre, pero en diferente orden

SoloPilot
fuente
2

Encontré este problema hoy, y en mi búsqueda de una respuesta a este mensaje de error informativo mínimo, también encontré este enlace:

https://connect.microsoft.com/SQLServer/feedback/details/339410/please-fix-the-string-or-binary-data-would-be-truncated-message-to-give-the-column-name

Por lo tanto, parece que Microsoft no tiene planes de expandir el mensaje de error en el corto plazo.

Entonces recurrí a otros medios.

Copié los errores para sobresalir:

(1 fila (s) afectada)

(1 fila (s) afectada)

(1 fila (s) afectada) Msg 8152, Nivel 16, Estado 14, Línea 13 La cadena o los datos binarios se truncarían. La instrucción se ha terminado.

(1 fila (s) afectada)

conté el número de filas en Excel, me acerqué al contador de registros que causó el problema ... ajusté mi código de exportación para imprimir el SQL cerca de él ... luego ejecuté las inserciones de 5 a 10 sql alrededor del problema sql y logró identificar el problema uno, ver la cadena que era demasiado larga, aumentar el tamaño de esa columna y luego el archivo de importación grande no funcionó.

Un poco hack y una solución alternativa, pero cuando te fuiste con muy pocas opciones, haces lo que puedes.

Shaakir
fuente
2

Sí, también me enfrento a este tipo de problema.

REMARKS VARCHAR(500)
to
REMARKS VARCHAR(1000)

Aquí, he cambiado la longitud del archivo OBSERVACIONES de 500 a 1000

Thivan Mydeen
fuente
2

Voy a agregar otra posible causa de este error solo porque nadie lo ha mencionado y podría ayudar a alguna persona futura (ya que el OP ha encontrado su respuesta). Si la tabla en la que está insertando tiene activadores, podría ser que el activador esté generando el error. He visto que esto sucede cuando se cambiaron las definiciones de los campos de la tabla, pero no las de auditoría.

HLGEM
fuente
2

Sí, "una pinta en una olla de media pinta no irá". No he tenido mucha suerte (por el motivo que sea) con los diversos SP que la gente ha sugerido, PERO siempre y cuando las dos tablas estén en la misma base de datos (o puede incluirlas en la misma base de datos), puede usar INFORMATION_SCHEMA. COLUMNAS para localizar los campos errantes, por lo tanto:

select c1.table_name,c1.COLUMN_NAME,c1.DATA_TYPE,c1.CHARACTER_MAXIMUM_LENGTH,c2.table_name,c2.COLUMN_NAME, c2.DATA_TYPE,c2.CHARACTER_MAXIMUM_LENGTH
from [INFORMATION_SCHEMA].[COLUMNS] c1
left join [INFORMATION_SCHEMA].[COLUMNS] c2 on 
c1.COLUMN_NAME=c2.COLUMN_NAME
where c1.TABLE_NAME='MyTable1'
and c2.TABLE_NAME='MyTable2'
--and c1.DATA_TYPE<>c2.DATA_TYPE
--and c1.CHARACTER_MAXIMUM_LENGTH <> c2.CHARACTER_MAXIMUM_LENGTH
order by c1.COLUMN_NAME

Esto le permitirá desplazarse hacia arriba y hacia abajo, comparando las longitudes de campo a medida que avanza. Las secciones comentadas le permiten ver (una vez sin comentar, obviamente) si hay desajustes de tipos de datos, o muestran específicamente aquellos que difieren en la longitud del campo, porque soy demasiado vago para desplazarse, solo tenga en cuenta que todo se basa en la fuente nombres de columna que coinciden con los del objetivo.

Kevin Anderson
fuente
Iba a escribir algo como esto, pero lo hiciste fácil. Muy práctico y trabajado como un encanto. Pude usarlo para comparar una tabla con más de 90 columnas y dos de ellas saltaron de inmediato. ¡Gracias!
Joy Walker
1

Estaba usando una cadena vacía '' en la creación de la tabla y luego recibí el error 'Msg 8152, la cadena o los datos binarios se truncarían' en la actualización posterior. Esto sucedía debido a que el valor de actualización contenía 6 caracteres y era más grande que la definición de columna anticipada. Utilicé "ESPACIO" para solucionar esto solo porque sabía que estaría actualizando en masa después de la creación de datos inicial, es decir, la columna no iba a permanecer vacía por mucho tiempo.

TAN GRANDE CUEVA AQUÍ: Esta no es una solución particularmente ingeniosa, pero es útil en el caso de que esté reuniendo un conjunto de datos, por ejemplo, para solicitudes de inteligencia únicas en las que está creando una tabla para la minería de datos, aplicando un procesamiento / interpretación masiva y almacenamiento de resultados antes y después para una comparación / extracción posterior. Este es un hecho frecuente en mi línea de trabajo.

Inicialmente puede completar utilizando la palabra clave ESPACIO, es decir

    select 
           Table1.[column1]
          ,Table1.[column2]
          ,SPACE(10) as column_name
    into table_you_are_creating
    from Table1
    where ...

Las actualizaciones posteriores a "column_name" de 10 caracteres o menos (sustitúyalas según corresponda) se permitirán sin causar un error truncado. Nuevamente, solo usaría esto en escenarios similares a los descritos en mi advertencia.

Hilario
fuente
1

He creado un procedimiento almacenado que analiza una tabla o consulta de origen con varias características por columna, entre las que se incluyen la longitud mínima (min_len) y la longitud máxima (max_len).

CREATE PROCEDURE [dbo].[sp_analysetable] (
  @tableName varchar(8000),
  @deep bit = 0
) AS

/*
sp_analysetable 'company'
sp_analysetable 'select * from company where name is not null'
*/

DECLARE @intErrorCode INT, @errorMSG VARCHAR(500), @tmpQ NVARCHAR(2000), @column_name VARCHAR(50), @isQuery bit
SET @intErrorCode=0

IF OBJECT_ID('tempdb..##tmpTableToAnalyse') IS NOT NULL BEGIN
  DROP TABLE ##tmpTableToAnalyse
END
IF OBJECT_ID('tempdb..##tmpColumns') IS NOT NULL BEGIN
  DROP TABLE ##tmpColumns
END

if CHARINDEX('from', @tableName)>0
  set @isQuery=1

IF @intErrorCode=0 BEGIN
  if @isQuery=1 begin
    --set @tableName = 'USE '+@db+';'+replace(@tableName, 'from', 'into ##tmpTableToAnalyse from')
    --replace only first occurance. Now multiple froms may exists, but first from will be replaced with into .. from
    set @tableName=Stuff(@tableName, CharIndex('from', @tableName), Len('from'), 'into ##tmpTableToAnalyse from')
    exec(@tableName)
    IF OBJECT_ID('tempdb..##tmpTableToAnalyse') IS NULL BEGIN
      set @intErrorCode=1
      SET @errorMSG='Error generating temporary table from query.'
    end
    else begin
      set @tableName='##tmpTableToAnalyse'
    end
  end
end

IF @intErrorCode=0 BEGIN
  SET @tmpQ='USE '+DB_NAME()+';'+CHAR(13)+CHAR(10)+'
  select
    c.column_name as [column],
    cast(sp.value as varchar(1000)) as description,
    tc_fk.constraint_type,
    kcu_pk.table_name as fk_table,
    kcu_pk.column_name as fk_column,
    c.ordinal_position as pos,
    c.column_default as [default],
    c.is_nullable as [null],
    c.data_type,
    c.character_maximum_length as length,
    c.numeric_precision as [precision],
    c.numeric_precision_radix as radix,
    cast(null as bit) as [is_unique],
    cast(null as int) as min_len,
    cast(null as int) as max_len,
    cast(null as int) as nulls,
    cast(null as int) as blanks,
    cast(null as int) as numerics,
    cast(null as int) as distincts,
    cast(null as varchar(500)) as distinct_values,
    cast(null as varchar(50)) as remarks
  into ##tmpColumns'
  if @isQuery=1 begin
    SET @tmpQ=@tmpQ+' from tempdb.information_schema.columns c, (select null as value) sp'
  end
  else begin
    SET @tmpQ=@tmpQ+'
      from information_schema.columns c
      left join sysobjects so    on so.name=c.table_name  and so.xtype=''U''
      left join syscolumns sc    on sc.name=c.column_name and sc.id  =so.id 
      left join sys.extended_properties sp on sp.minor_id = sc.colid AND sp.major_id = sc.id and sp.name=''MS_Description''  
      left join information_schema.key_column_usage kcu_fk    on kcu_fk.table_name = c.table_name     and c.column_name = kcu_fk.column_name
      left join information_schema.table_constraints tc_fk    on kcu_fk.table_name = tc_fk.table_name and kcu_fk.constraint_name = tc_fk.constraint_name
      left join information_schema.referential_constraints rc on rc.constraint_name = kcu_fk.constraint_name
      left join information_schema.table_constraints tc_pk    on rc.unique_constraint_name = tc_pk.constraint_name
      left join information_schema.key_column_usage kcu_pk    on tc_pk.constraint_name = kcu_pk.constraint_name
 '
  end
  SET @tmpQ=@tmpQ+' where c.table_name = '''+@tableName+''''

  exec(@tmpQ)
end

IF @intErrorCode=0 AND @deep = 1 BEGIN
  DECLARE
    @count_rows int,
    @count_distinct int,
    @count_nulls int,
    @count_blanks int,
    @count_numerics int,
    @min_len int,
    @max_len int,
    @distinct_values varchar(500)
  DECLARE curTmp CURSOR LOCAL FAST_FORWARD FOR
    select [column] from ##tmpColumns;
  OPEN curTmp
  FETCH NEXT FROM curTmp INTO @column_name
  WHILE @@FETCH_STATUS = 0 and @intErrorCode=0 BEGIN
    set @tmpQ = 'USE '+DB_NAME()+'; SELECT'+
      '  @count_rows=count(0), '+char(13)+char(10)+
      '  @count_distinct=count(distinct ['+@column_name+']),'+char(13)+char(10)+
      '  @count_nulls=sum(case when ['+@column_name+'] is null then 1 else 0 end),'+char(13)+char(10)+
      '  @count_blanks=sum(case when ltrim(['+@column_name+'])='''' then 1 else 0 end),'+char(13)+char(10)+
      '  @count_numerics=sum(isnumeric(['+@column_name+'])),'+char(13)+char(10)+
      '  @min_len=min(len(['+@column_name+'])),'+char(13)+char(10)+
      '  @max_len=max(len(['+@column_name+']))'+char(13)+char(10)+
      ' from ['+@tableName+']'
    exec sp_executesql @tmpQ,
                       N'@count_rows int OUTPUT,
                         @count_distinct int OUTPUT,
                         @count_nulls int OUTPUT,
                         @count_blanks int OUTPUT,
                         @count_numerics int OUTPUT,
                         @min_len int OUTPUT,
                         @max_len int OUTPUT',
                       @count_rows     OUTPUT,
                       @count_distinct OUTPUT,
                       @count_nulls    OUTPUT,
                       @count_blanks    OUTPUT,
                       @count_numerics OUTPUT,
                       @min_len        OUTPUT,
                       @max_len        OUTPUT

    IF (@count_distinct>10) BEGIN
      SET @distinct_values='Many ('+cast(@count_distinct as varchar)+')'
    END ELSE BEGIN
      set @distinct_values=null
      set @tmpQ = N'USE '+DB_NAME()+';'+
        '  select @distinct_values=COALESCE(@distinct_values+'',''+cast(['+@column_name+'] as varchar),  cast(['+@column_name+'] as varchar))'+char(13)+char(10)+
        '  from ('+char(13)+char(10)+
        '    select distinct ['+@column_name+'] from ['+@tableName+'] where ['+@column_name+'] is not null) a'+char(13)+char(10)
      exec sp_executesql @tmpQ,
                         N'@distinct_values varchar(500) OUTPUT',
                         @distinct_values        OUTPUT
    END
    UPDATE ##tmpColumns SET
      is_unique      =case when @count_rows=@count_distinct then 1 else 0 end,
      distincts      =@count_distinct,
      nulls          =@count_nulls,
      blanks         =@count_blanks,
      numerics       =@count_numerics,
      min_len        =@min_len,
      max_len        =@max_len,
      distinct_values=@distinct_values,
      remarks       =
        case when @count_rows=@count_nulls then 'all null,' else '' end+
        case when @count_rows=@count_distinct then 'unique,' else '' end+
        case when @count_distinct=0 then 'empty,' else '' end+
        case when @min_len=@max_len then 'same length,' else '' end+
        case when @count_rows=@count_numerics then 'all numeric,' else '' end
    WHERE [column]=@column_name

    FETCH NEXT FROM curTmp INTO @column_name
  END
  CLOSE curTmp DEALLOCATE curTmp
END

IF @intErrorCode=0 BEGIN
  select * from ##tmpColumns order by pos
end

IF @intErrorCode=0 BEGIN --Clean up temporary tables
  IF OBJECT_ID('tempdb..##tmpTableToAnalyse') IS NOT NULL BEGIN
    DROP TABLE ##tmpTableToAnalyse
  END
  IF OBJECT_ID('tempdb..##tmpColumns') IS NOT NULL BEGIN
    DROP TABLE ##tmpColumns
  END
end

IF @intErrorCode<>0 BEGIN
  RAISERROR(@errorMSG, 12, 1)
END
RETURN @intErrorCode

Guardo este procedimiento en la base de datos maestra para poder usarlo en todas las bases de datos así:

sp_analysetable 'table_name', 1
// deep=1 for doing value analyses

Y la salida es:

column description constraint_type fk_table fk_column pos default null data_type length precision radix is_unique min_len max_len nulls blanks numerics distincts distinct_values remarks
id_individual NULL PRIMARY KEY NULL NULL 1 NULL NO int NULL 10 10 1 1 2 0 0 70 70 Many (70) unique,all numeric,
id_brand NULL NULL NULL NULL 2 NULL NO int NULL 10 10 0 1 1 0 0 70 2 2,3 same length,all numeric, guid NULL NULL NULL NULL 3 (newid()) NO uniqueidentifier NULL NULL NULL 1 36 36 0 0 0 70 Many (70) unique,same length,
customer_id NULL NULL NULL NULL 4 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
email NULL NULL NULL NULL 5 NULL YES varchar 100 NULL NULL 0 4 36 0 0 0 31 Many (31)
mobile NULL NULL NULL NULL 6 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
initials NULL NULL NULL NULL 7 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
title_short NULL NULL NULL NULL 8 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
title_long NULL NULL NULL NULL 9 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
firstname NULL NULL NULL NULL 10 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
lastname NULL NULL NULL NULL 11 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
address NULL NULL NULL NULL 12 NULL YES varchar 100 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
pc NULL NULL NULL NULL 13 NULL YES varchar 10 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
kixcode NULL NULL NULL NULL 14 NULL YES varchar 20 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
date_created NULL NULL NULL NULL 15 (getdate()) NO datetime NULL NULL NULL 1 19 19 0 0 0 70 Many (70) unique,same length,
created_by NULL NULL NULL NULL 16 (user_name()) NO varchar 50 NULL NULL 0 13 13 0 0 0 1 loyalz-public same length,
id_location_created NULL FOREIGN KEY location id_location 17 NULL YES int NULL 10 10 0 1 1 0 0 70 2 1,2 same length,all numeric, id_individual_type NULL FOREIGN KEY individual_type id_individual_type 18 NULL YES int NULL 10 10 0 NULL NULL 70 0 0 0 NULL all null,empty,
optin NULL NULL NULL NULL 19 NULL YES int NULL 10 10 0 1 1 39 0 31 2 0,1 same length,

Christiaan Westerbeek
fuente
Nota al margen: se debe no utilizar el sp_prefijo para los procedimientos almacenados. Microsoft ha reservado ese prefijo para su propio uso (consulte Procedimientos almacenados de nomenclatura ) , y corre el riesgo de un choque de nombres en algún momento en el futuro. También es malo para el rendimiento de su procedimiento almacenado . Es mejor simplemente evitar sp_y usar algo más como prefijo, ¡o sin prefijo!
marc_s
1

Escribí un procedimiento de almacenamiento útil para ayudar a identificar y resolver el problema del truncamiento de texto (la cadena o los datos binarios se truncarían) cuando se usa la instrucción INSERT SELECT. Compara los campos CHAR, VARCHAR, NCHAR Y NVARCHAR únicamente y devuelve un campo de evaluación campo por campo en caso de ser la posible causa del error.

EXEC dbo.GetFieldStringTruncate SourceTableName, TargetTableName

Este procedimiento almacenado está orientado al problema del truncamiento de texto cuando se realiza una instrucción INSERT SELECT.

El funcionamiento de este procedimiento almacenado depende de que el usuario identifique previamente la instrucción INSERT con el problema. Luego insertando los datos de origen en una tabla temporal global. Se recomienda la instrucción SELECT INTO.

Debe usar el mismo nombre del campo de la tabla de destino en el alias de cada campo de la instrucción SELECT.

CÓDIGO DE FUNCIÓN:

DECLARE @strSQL nvarchar(1000)
IF NOT EXISTS (SELECT * FROM dbo.sysobjects where id = OBJECT_ID(N'[dbo].[GetFieldStringTruncate]'))
    BEGIN
        SET @strSQL = 'CREATE PROCEDURE [dbo].[GetFieldStringTruncate] AS RETURN'
        EXEC sys.sp_executesql @strSQL
    END

GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

/*
------------------------------------------------------------------------------------------------------------------------
    Description:    
                    Syntax 
                    ---------------
                    dbo.GetFieldStringTruncate(SourceTable, TargetTable)
                    +---------------------------+-----------------------+
                    |   SourceTableName         |   VARCHAR(255)        |
                    +---------------------------+-----------------------+
                    |   TargetTableName         |   VARCHAR(255)        |
                    +---------------------------+-----------------------+

                    Arguments
                    ---------------
                    SourceTableName
                    The name of the source table. It should be a temporary table using double charp '##'. E.g. '##temp'

                    TargetTableName
                    The name of the target table. It is the table that receives the data used in the INSERT INTO stament.

                    Return Type
                    ----------------
                    Returns a table with a list of all the fields with the type defined as text and performs an evaluation indicating which field would present the problem of string truncation.

                    Remarks
                    ----------------
                    This stored procedure is oriented to the problem of text truncation when an INSERT SELECT statement is made.
                    The operation of this stored procedure depends on the user previously identifying the INSERT statement with the problem. Then inserting the source data into a global temporary table. The SELECT INTO statement is recommended.
                    You must use the same name of the field of the destination table in the alias of each field of the SELECT statement.

                    Examples
                    ====================================================================================================

                    --A. Test basic

                        IF EXISTS (SELECT * FROM sys.objects  WHERE OBJECT_ID = OBJECT_ID(N'[dbo].[tblDestino]') AND TYPE IN (N'U'))
                            DROP TABLE tblDestino

                        CREATE TABLE tblDestino
                        (
                            Id INT IDENTITY,
                            Field1 VARCHAR(10),
                            Field2 VARCHAR(12),
                            Field3 VARCHAR(11),
                            Field4 VARCHAR(16),
                            Field5 VARCHAR(5),
                            Field6 VARCHAR(1),
                            Field7 VARCHAR(1),
                            Field8 VARCHAR(6),
                            Field9 VARCHAR(6),
                            Field10 VARCHAR(50),
                            Field11 VARCHAR(50),
                            Field12 VARCHAR(50)
                        )

                        INSERT INTO dbo.tblDestino
                        (
                             Field1 ,
                             Field2 ,
                             Field3 ,
                             Field4 ,
                             Field5 ,
                             Field6 ,
                             Field7 ,
                             Field8 ,
                             Field9 ,
                             Field10 ,
                             Field11 ,
                             Field12
                            )
                        SELECT 
                             '123456789' , -- Field1 - varchar(10)
                             '123456789' , -- Field2 - varchar(12)
                             '123456789' , -- Field3 - varchar(11)
                             '123456789' , -- Field4 - varchar(16)
                             '123456789' , -- Field5 - varchar(5)
                             '123456789' , -- Field6 - varchar(1)
                             '123456789' , -- Field7 - varchar(1)
                             '123456789' , -- Field8 - varchar(6)
                             '123456789' , -- Field9 - varchar(6)
                             '123456789' , -- Field10 - varchar(50)
                             '123456789' , -- Field11 - varchar(50)
                             '123456789'  -- Field12 - varchar(50)
                        GO  

                    Result:
                        String or binary data would be truncated


                    *Here you get the truncation error. Then, we proceed to save the information in a global temporary table. 
                    *IMPORTANT REMINDER: You must use the same name of the field of the destination table in the alias of each field of the SELECT statement.


                    Process:

                        IF OBJECT_ID('tempdb..##TEMP') IS NOT NULL DROP TABLE ##TEMP
                        go
                        SELECT 
                             [Field1] = '123456789' ,
                             [Field2] = '123456789' ,
                             [Field3] = '123456789' ,
                             [Field4] = '123456789' ,
                             [Field5] = '123456789' ,
                             [Field6] = '123456789' ,
                             [Field7] = '123456789' ,
                             [Field8] = '123456789' ,
                             [Field9] = '123456789' ,
                             [Field10] = '123456789' ,
                             [Field11] = '123456789' ,
                             [Field12] = '123456789'  
                        INTO ##TEMP

                    Result:
                    (1 row(s) affected)

                    Test:
                        EXEC dbo.GetFieldStringTruncate @SourceTableName = '##TEMP', @TargetTableName = 'tblDestino'

                    Result:

                        (12 row(s) affected)
                        ORIGEN Nombre Campo        ORIGEN Maximo Largo  DESTINO Nombre Campo     DESTINO Tipo de campo   Evaluación
                        -------------------------- -------------------- ------------------------ ----------------------- -------------------------
                        Field1                     9                    02 - Field1              VARCHAR(10)             
                        Field2                     9                    03 - Field2              VARCHAR(12)             
                        Field3                     9                    04 - Field3              VARCHAR(11)             
                        Field4                     9                    05 - Field4              VARCHAR(16)             
                        Field5                     9                    06 - Field5              VARCHAR(5)              possible field with error
                        Field6                     9                    07 - Field6              VARCHAR(1)              possible field with error
                        Field7                     9                    08 - Field7              VARCHAR(1)              possible field with error
                        Field8                     9                    09 - Field8              VARCHAR(6)              possible field with error
                        Field9                     9                    10 - Field9              VARCHAR(6)              possible field with error
                        Field10                    9                    11 - Field10             VARCHAR(50)             
                        Field11                    9                    12 - Field11             VARCHAR(50)             
                        Field12                    9                    13 - Field12             VARCHAR(50)             

                    ====================================================================================================

    ------------------------------------------------------------------------------------------------------------

    Responsible:    Javier Pardo 
    Date:           October 19/2018
    WB tests:       Javier Pardo 

    ------------------------------------------------------------------------------------------------------------

*/

ALTER PROCEDURE dbo.GetFieldStringTruncate
(
    @SourceTableName AS VARCHAR(255)
    , @TargetTableName AS VARCHAR(255)
)
AS
BEGIN
    BEGIN TRY

        DECLARE @colsUnpivot AS NVARCHAR(MAX),
            @colsUnpivotConverted AS NVARCHAR(MAX),
           @query  AS NVARCHAR(MAX)

        SELECT @colsUnpivot = stuff((
                    SELECT DISTINCT ',' + QUOTENAME(col.NAME)
                    FROM tempdb.sys.tables tab
                    INNER JOIN tempdb.sys.columns col
                        ON col.object_id = tab.object_id
                    INNER JOIN tempdb.sys.types typ
                        ON col.system_type_id = TYP.system_type_id
                    WHERE tab.NAME = @SourceTableName
                    FOR XML path('')
                    ), 1, 1, '')
                ,@colsUnpivotConverted = stuff((
                    SELECT DISTINCT ',' + 'CONVERT(VARCHAR(MAX),' + QUOTENAME(col.NAME) + ') AS ' + QUOTENAME(col.NAME)
                    FROM tempdb.sys.tables tab
                    INNER JOIN tempdb.sys.columns col
                        ON col.object_id = tab.object_id
                    INNER JOIN tempdb.sys.types typ
                        ON col.system_type_id = TYP.system_type_id
                    WHERE tab.NAME = @SourceTableName
                    FOR XML path('')
                    ), 1, 1, '')


        --/programming/11158017/column-conflicts-with-the-type-of-other-columns-in-the-unpivot-list
        IF OBJECT_ID('tempdb..##TablaConMaximos') IS NOT NULL DROP TABLE ##TablaConMaximos

        set @query 
          = 'SELECT u.d AS colname, MAX(LEN(u.data)) as [maximo_largo]
            INTO ##TablaConMaximos
            FROM 
            (
                SELECT ' + @colsUnpivotConverted + '
                FROM ' + @SourceTableName + '
            ) T
            UNPIVOT
             (
                data
                for d in ('+ @colsunpivot +')
             ) u
             GROUP BY u.d'

        PRINT @query

        exec sp_executesql @query;

        ------------------------------------------------------------------------------------------------------------
        SELECT --'Nombre de campo' = RIGHT('00' + ISNULL(CONVERT(VARCHAR,col.column_id),''),2) + ' - ' + col.name + ' '
            --, 'Tipo de campo' = ISNULL(CONVERT(VARCHAR,upper(typ.name)),'') + '(' + ISNULL(CONVERT(VARCHAR,col.max_length),'') + ')'
            [ORIGEN Nombre Campo] = tcm.colname
            , [ORIGEN Maximo Largo] = tcm.maximo_largo
            , [DESTINO Nombre Campo] = DESTINO.[Nombre de campo]
            , [DESTINO Tipo de campo] = DESTINO.[Tipo de campo]
            , [Evaluación] = CASE WHEN DESTINO.maximo_largo < tcm.maximo_largo THEN 'possible field with error' ELSE '' END
            --, * 
        FROM tempdb.sys.tables tab
            INNER JOIN tempdb.sys.columns col
                ON col.object_id = tab.object_id
            INNER JOIN tempdb.sys.types typ
                ON col.system_type_id = TYP.system_type_id
            RIGHT JOIN 
                (
                    SELECT column_id
                        , [Nombre de campo] = RIGHT('00' + ISNULL(CONVERT(VARCHAR,col.column_id),''),2) + ' - ' + col.name + ' '
                        , [Tipo de campo] = ISNULL(CONVERT(VARCHAR,upper(typ.name)),'') + '(' + ISNULL(CONVERT(VARCHAR,col.max_length),'') + ')'
                        , [maximo_largo] = col.max_length
                        , [colname] = col.name
                    FROM sys.tables tab
                        INNER JOIN sys.columns col
                            ON col.object_id = tab.object_id
                        INNER JOIN sys.types typ
                            ON col.system_type_id = TYP.system_type_id
                    WHERE tab.NAME = @TargetTableName
                ) AS DESTINO
                    ON col.name = DESTINO.colname
            INNER JOIN ##TablaConMaximos tcm
                ON tcm.colname = DESTINO.colname

        WHERE tab.NAME = @SourceTableName
            AND typ.name LIKE '%char%'
        ORDER BY col.column_id

    END TRY
    BEGIN CATCH
        SELECT 'Internal error ocurred' AS Message
    END CATCH   

END

Por ahora solo admite los tipos de datos CHAR, VARCHAR, NCHAR y NVARCHAR . Puede encontrar la última versión de este código en el siguiente enlace a continuación y nos ayudamos mutuamente a mejorarlo. GetFieldStringTruncate.sql

https://gist.github.com/jotapardo/210e85338f87507742701aa9d41cc51d

JotaPardo
fuente
1

Si está utilizando SQL Server 2016-2017: para solucionarlo, active la marca de seguimiento 460

DBCC TRACEON(460, 1);
GO

y asegúrese de apagarlo después de:

DBCC TRACEOFF(460, 1);
GO

fuente

nimajv
fuente
0

Esto también puede ocurrir cuando no tienes los permisos adecuados

Galleta128
fuente
2
De Verdad? ¿Un error real de 'Cadena o datos binarios se truncaría'? Eso parece un error muy extraño si no tienes permisos. ¿Existe un permiso que le impide escribir más de una cierta cantidad de datos? (Estoy interesado porque quiero verificar el tamaño del campo automáticamente cuando recibo este error, así que si ocurre por alguna otra razón, ¡eso es muy interesante!)
Ian Grainger
0

Tuve un problema similar Estaba copiando datos de una tabla a una tabla idéntica en todo menos en el nombre.

Eventualmente volqué la tabla fuente en una tabla temporal usando una instrucción SELECT INTO.

SELECT *
INTO TEMP_TABLE
FROM SOURCE_TABLE;

Comparé el esquema de la tabla fuente con la tabla temporal. Encontré que una de las columnas era un varchar(4000)cuando esperaba un varchar(250).

ACTUALIZACIÓN: El problema varchar (4000) se puede explicar aquí en caso de que esté interesado:

Para Nvarchar (Max), ¿solo obtengo 4000 caracteres en TSQL?

Espero que esto ayude.

Warren Banks
fuente
0

Este error se produce cuando la columna de una tabla pone restricciones [principalmente longitud]. . Por ejemplo, si el esquema de la base de datos para la columna myColumn es CHAR (2), cuando llame desde cualquiera de sus aplicaciones para insertar valor, debe pasar una cadena de longitud dos.

El error básicamente lo dice; la cadena de longitud tres y superior es inconsistente para ajustarse a la restricción de longitud especificada por el esquema de la base de datos. Es por eso que SQL Server advierte y arroja la pérdida de datos / error de truncamiento.

Yergalem
fuente
0

Por favor, intente el siguiente código:

CREATE TABLE [dbo].[Department](
    [Department_name] char(10) NULL
)

INSERT INTO [dbo].[Department]([Department_name]) VALUES  ('Family Medicine')
--error will occur

 ALTER TABLE [Department] ALTER COLUMN [Department_name] char(50)

INSERT INTO [dbo].[Department]([Department_name]) VALUES  ('Family Medicine')

select * from [Department]
arnav
fuente