2010-09-08 27 views
7

Imagine una tabla con un centenar de columnas diferentes. Imagínese, entonces, que tengo una tabla de datos de usuario desde donde quiero copiar datos a la tabla base. Así que escribí esta simple instrucción insertar-seleccionar y este error aparece. Entonces, ¿cuál es la forma más elegante de averiguar qué columna plantea el error?¿Cómo saber qué columna genera un error de desbordamiento aritmético al insertar?

Mis pensamientos iniciales sobre la solución están a punto de envolverlo en una transacción que voy a deshacer en última instancia, y el uso de una especie de Divide y vencerás:

begin tran 

insert into BaseTable (c1,c2,c3,...,cN) 
select c1,c2,c3,...,cN 
from UserTable 

rollback tran 

Y esto falla, obviamente. Así dividimos el conjunto de columnas en la mitad de este modo:

begin tran 

insert into BaseTable (c1,c2,c3,...,cK) --where K = N/2 
select c1,c2,c3,...,cK --where K = N/2 
from UserTable 

rollback tran 

Y si falla, entonces la columna no está en la otra mitad. Y continuamos el proceso, hasta que encontremos la molesta columna.

¿Algo más elegante que eso?

Nota: También encontré un casi duplicado de esta pregunta, pero apenas lo responde.

+0

Si hace coincidir los tipos de datos de UserTable con los de BaseTable, su inserción no debería tener ningún problema. Todo lo que se necesita después de eso es encontrar la columna ofensiva * UserTable * . –

+0

@Lieven Bueno, UserTable es solo eso ... una tabla de usuario sin restricciones, porque los datos que contiene son de Excel o Access o lo que sea. –

+0

Me solidarizo. Si esto es algo que debe hacerse de manera regular, ¿no podría crear un script/procedimiento almacenado que verifique sus entradas? Una macro y una simple selección llegarían muy lejos, algo así como 'SELECCIONAR' c1 ', CAST (c1) COMO INTEGER FROM UserTable'. –

Respuesta

6

siguiente script crearía SELECT declaraciones para cada columna entera de Basetable.
La ejecución de las declaraciones resultantes SELECT debe identificar las columnas infractoras en su Usertable.

SELECT 'PRINT ''' 
     + sc.Name 
     + '''; SELECT MIN(CAST(' 
     + sc.Name 
     + ' AS INTEGER)) FROM Usertable' 
FROM sys.columns sc 
     INNER JOIN sys.types st ON st.system_type_id = sc.system_type_id 
WHERE OBJECT_NAME(Object_ID) = 'BaseTable' 
     AND st.name = 'INT' 
+0

Guau, me gusta este enfoque. –

-1

Muchas veces el método de fuerza bruta que sugiere es la mejor manera.

Sin embargo, si tiene una copia de la base de datos, también puede publicar datos falsos.

ejecutar la consulta en él, por lo que no tiene acerca de la transcation que oculta la columna que la está rompiendo. A veces, en el error, dará una pista sobre lo que está sucediendo. Por lo general, si estás mirando lo que está entrando, puedes ver cuándo está entrando texto en un int o viceversa.

Hago esto y eso quita cualquier otra cosa en mi código que causa el problema.

Debe obtener una copia de la consulta que se genera donde puede copiarla y pegarla en una herramienta de consulta.

+0

Sí, dice: Desbordamiento aritmético en varbinary con valor 1239847234.000000. O algo por el estilo. Definitivamente puedo leer el mensaje de error, pero eso no me ayuda de ninguna manera. –

+0

¿Son todos los valores que está sacando de varchar y todo lo que está insertando en varchar? porque los varbinary tienden a hacerme pensar que esto no es verdad. –

+0

Columnas en BaseTable y UserTable son lo mismo en otras palabras? –

-1

Creo que está tomando un enfoque equivocado. Si obtiene un desbordamiento aritmético simplemente seleccionando columnas de una tabla e insertándolas en otra, entonces debe seleccionar de colimns más grandes (por ejemplo, bigint) e insertarlas en columnas pequeñas (por ejemplo, int). Esto es algo fundamentalmente incorrecto y debe modificar su estructura de base de datos para que funcione la inserción de filas de una tabla a otra. Inspeccione cada columna de cada tabla y vea dónde es posible obtener un desbordamiento, luego ajuste su tabla de destino para que quepan los datos que está insertando.

Sigo pensando que mi punto de vista es correcto, pero en respuesta a sus comentarios si quiere una solución rápida y sucia. Haga todas sus columnas en Varchar BaseTable (MAX).

continuación:

insert into BaseTable (c1,c2,...,cN) 
select CAST(c1 AS varchar(max)),CAST(c2 AS varchar(max))...,cN 
from UserTable 
+2

No, no veo ningún defecto en mi enfoque. No tengo control sobre la UserTable y todas las columnas allí son varchar. Solo quiero una manera rápida y sucia de averiguar qué columna causa un error. Es solo una carga inicial de datos y no debería tomar mucho tiempo verificar esto o aquello. ¿Sabes a lo que me refiero? –

+1

Y eso no responde mi pregunta, eso es evadirlo. –

+0

Todas las columnas son varchar? ¿Todos ellos? –

0

Si esto es sólo algo que se está ejecutando de forma manual a continuación, dependiendo de la cantidad de datos que va a insertar se puede utilizar la cláusula OUTPUT a la salida de las filas insertadas al cliente.

La fila después de la última salida debe ser la que tenga el problema.

+0

Digamos que tengo solo una fila con muchas columnas. :) –

+0

Entonces solo necesita mirar la fila. – Sam

+2

@Sam, te estás perdiendo el punto. No es la cantidad de filas lo que es problemático, sino la cantidad de columnas. –

0

Adopté el enfoque de Lieven Keersmaekers pero lo extendí. Si una tabla tiene varias longitudes de campo numéricas, esta secuencia de comandos cambiará el Cast según el nombre y la precisión del tipo. El crédito aún le va a Lieven por pensar en esta solución, me ayudó mucho.

DECLARE @tableName VARCHAR(100) 

SET @tableName = 'tableName' 

SELECT 'PRINT ''' + sc.NAME + '''; SELECT MIN(CAST([' + sc.NAME + '] as ' + CASE 
     WHEN st.NAME = 'int' 
      THEN 'int' 
     ELSE st.NAME + '(' + cast(sc.precision AS VARCHAR(5)) + ',' + cast(sc.scale AS VARCHAR(5)) + ')' 
     END + ')) from ' + @tableName 
FROM sys.columns sc 
INNER JOIN sys.types st ON st.system_type_id = sc.system_type_id 
WHERE OBJECT_NAME(Object_ID) = @tableName 
    AND st.NAME NOT IN ('nvarchar', 'varchar', 'image', 'datetime', 'smalldatetime', 'char', 'nchar') 
Cuestiones relacionadas