¿Cómo identifico las columnas responsables de “ La cadena o los datos binarios se truncarían. ”

Estoy generando algunas consultas automágicamente con el código que escribí para SELECT desde una base de datos Pg remota e inserto en una base de datos local de SQL Server. Sin embargo, uno de ellos genera este error:

[Microsoft] [ODBC SQL Server Driver] [SQL Server] La cadena o los datos binarios se truncarían. (SQL-22001) [el estado era 22001 ahora 01000]

[Microsoft] [ODBC SQL Server Driver] [SQL Server] La declaración ha finalizado. (SQL-01000) en. \ Insert.pl línea 106.

¿Cómo averiguo qué columna está generando ese error y carece de la longitud del ¿aporte? ¿Hay alguna manera de hacer esto sin adivinar por fuerza bruta todas las varchar?

Respuesta

No, no se registra en ninguna parte. Vaya a votar y exponga su caso comercial; este es uno en la larga lista de cosas que deberían arreglarse en SQL Server.

Esto se solicitó hace años en Connect (probablemente primero en el período de tiempo de SQL Server 2000 o 2005), luego nuevamente en el nuevo sistema de comentarios:

Y ahora se ha entregado en las siguientes versiones:

En la primera CTP pública de SQL Server 2019, solo aparece bajo el indicador de seguimiento 460. Esto suena un poco secreto, pero se publicó en este documento técnico de Microsoft . Este será el comportamiento predeterminado (no se requiere una marca de seguimiento) en el futuro, aunque podrá controlarlo a través de una nueva configuración de base de datos VERBOSE_TRUNCATION_WARNINGS.

Aquí es un ejemplo:

USE tempdb; GO CREATE TABLE dbo.x(a char(1)); INSERT dbo.x(a) VALUES("foo"); GO 

Resultado en todas las versiones compatibles antes de SQL Server 2019:

Msg 8152, nivel 16, estado 30, línea 5
La cadena o los datos binarios se truncarían.
La declaración ha finalizado.

Ahora, en los CTP de SQL Server 2019, con la marca de seguimiento habilitada:

DBCC TRACEON(460); GO INSERT dbo.x(a) VALUES("foo"); GO DROP TABLE dbo.x; DBCC TRACEOFF(460); 

El resultado muestra la tabla, la columna y el ( truncado , no valor ) completo:

Msj 2628, nivel 16, estado 1, línea 11
La cadena o los datos binarios se truncarían en la tabla «tempdb.dbo.x», columna «a». Valor truncado: «f».
La declaración ha finalizado.

Hasta que pueda cambiar a una versión / CU compatible o cambiar a Azure SQL Database, puede cambiar su código «automagic» para extraer el max_length de sys.columns, junto con el nombre que debe obtener de todos modos, y luego aplicar LEFT(column, max_length) o lo que sea el equivalente de PG. O, dado que eso solo significa que perderá datos en silencio, averigüe qué columnas no coinciden y corrija las columnas de destino para que se ajusten a todos los datos de la fuente. Dado el acceso a los metadatos a ambos sistemas, y el hecho de que ya está escribiendo una consulta que debe coincidir automáticamente con la fuente -> las columnas de destino (de lo contrario, este error difícilmente sería su mayor problema), no debería tener que hacer ninguna fuerza bruta adivinando.

Respuesta

Si tiene acceso para ejecutar el Asistente de importación y exportación de SQL Server desde SQL Server Management Studio (haga clic con el botón derecho en la base de datos> Tareas> Importar datos …), cree una tarea que importe desde el Cliente SQL utilizando su consulta como fuente de datos a la tabla de destino.

Antes de ejecutar la importación, puede revisar la asignación de datos y le dirá qué columnas tienen tipos de campo inconsistentes. Y si ejecuta la tarea de importación, le indicará qué columna (s) no se pudieron importar.

Advertencia de validación de muestra:

Advertencia 0x802092a7: Tarea de flujo de datos 1: Puede producirse un truncamiento debido a la inserción de datos de la columna de flujo de datos «NARRATIVO» con una longitud de 316 en la columna de base de datos «NARRATIVO» con una longitud de 60. (Asistente de importación y exportación de SQL Server)

Responder

Finalmente Microsoft ha decidido proporcionar información significativa para String or binary would be truncated a partir de SQL Server 2016 SP2 CU, SQL Server 2017 CU12 y SQL Server 2019.

La información ahora incluye la columna de la tabla infractora (nombre completo) y el valor infractor (truncado en 120 caracteres):

Msj 2628, nivel 16, estado 1, La línea x String o los datos binarios se truncarían en la tabla «TheDb.TheSchema.TheTable «, columna» TheColumn «. Valor truncado:» … «. La declaración ha finalizado.

Respuesta

Al final, no pude encontrar una manera de obtener la información de la columna sin escribirla yo mismo.

Este mensaje de error fue generado por DBD::ODBC , sin embargo, también puedes usar sys.columns (max_length) (simplemente no sé cómo).

Usé un código como este en mi lista de columnas para obtener una lista de matrices con dos elementos, COLUMN_NAME y MAX_LENGTH (documentado en DBI column_info() ).

my @max_lengths = map [ @{$_->fetchall_arrayref->[0]}[3,6] ] , map $dbh_mssql->column_info("database", "dbo", $dest_table, $_) , @col_mssql ; 

Luego capté las excepciones en INSERT e imprimí algo útil. En este ejemplo, @$row son los datos enviados a sth->execute()

if ($@) { warn "$@\n"; for ( my $idx=0; $idx <= $#{ $row }; $idx++ ) { Dumper { maxlength => $max_lengths[$idx]->[1] , name => $max_lengths[$idx]->[0] , length => length( $row->[$idx] ) , content => $row->[$idx] }; } die; } 

Además, vote y vote a favor de la otra respuesta

Comentarios

  • I no ‘ puse ningún código que haga referencia a sys.columns porque no tenía ni idea de qué código estás usando actualmente para » Automágicamente » genera tus consultas. Realmente no hay ‘ t mucho más complejo que podría suponer incorporar en su código que SELECT name, object_id, max_length FROM sys.columns;. Como ya tiene un código automágico que debe estar haciendo esto, o algo muy parecido, no ‘ creía que fuera necesario un ejemplo.
  • I ‘ No estoy seguro de cómo funciona sys.columns con dos columnas que tienen el mismo name. Además, hice que la cosa funcionara usando la biblioteca en lugar de sys, ¿por qué debería hacer eso como la respuesta elegida? Microsoft SQL doesn't have x, do y instead es una contribución válida, pero si su y es inferior a mi y, ‘ voy a hacer algo diferente y marcarlo como elegido.
  • Su pregunta era, esencialmente, ¿cómo averiguo qué columna estaba generando el error (presumiblemente , para que pueda arreglar ese punto, en lugar de rediseñar la solución). Te dije dónde buscar: sys.columns. Que es exactamente donde debe buscar para comparar las longitudes de las columnas de origen con las longitudes de las columnas de destino. Cómo lo hagas depende de ti. No ‘ te dije cómo arreglar tu código, porque no tengo ni idea de cómo se estaba generando tu consulta automágica en primer lugar, así que, como dije, no tenía idea de cómo para agregar las determinaciones de longitud a cualquier consulta que ya tuviera.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *