2010-07-14 15 views

Respuesta

1

Puede verificar la longitud de cada valor insertado con una condición if, y si el valor necesita más ancho que el ancho de la columna actual, trunque el valor y arroje un error personalizado.

que debería funcionar si sólo tiene que identificar cuál es el campo de la causa del problema. No sé si hay una mejor manera de hacerlo.

+3

Claro, ese es el método que termino usando. Mi pregunta es, ¿por qué SQL Server no te dice dónde está * cuando encuentra el problema? * – harpo

0

No puedo pensar en una buena manera realmente.
Una vez pasé mucho tiempo depurando un mensaje muy informativo de "División por cero".

lo general, se comentan a cabo diversas piezas de código de salida para encontrar el que causa problemas.
Luego toma esta pieza que encontró y la hace devolver un valor que indica que hay un problema en lugar del valor real (en su caso, debería reemplazar la cadena de salida con el len(of the output)). Luego compare manualmente con la longitud de la columna en la que lo está insertando.

0

desde el número de línea en el mensaje de error, debe poder identificar la consulta de inserción que está causando el error. modificar eso en una consulta de selección para incluir AND LEN(your_expression_or_column_here) > CONSTANT_COL_INT_LEN para la cadena de varias columnas en su consulta. mira la salida y te dará las malas filas.

+0

Sí, estoy hablando cuando conoces la consulta. Y este es el tipo de depuración manual que trato de evitar. Podría haber muchas columnas en la tabla, y podría haber más de una causante del problema. Seguramente lo que está describiendo el trabajo de la computadora, ¿verdad? – harpo

+0

decirle a la computadora cómo manejar la excepción. evítelo en el DÓNDE, tirando las filas, trunquelas en su INSERT haciendo 'DERECHA (...., max_col_len_int)' y nunca obtenga este error, solo trunque. si desea que el programa lo maneje, use una consulta IF EXISTS antes de INSERT para encontrar cualquiera que trunque. Si diseñas tus tablas con los tipos de datos adecuados, esto no sucede. si está cargando datos externos, necesita codificar para manejar estas excepciones, ** SQL SERVER no puede leer su mente y hacer lo que USTED quiere, hace lo que dice el TSQL. ** –

+0

Sí, he recurrido a ese método bastante a menudo (aunque uso IZQUIERDA, por supuesto). Pero eso solo funciona para los campos de "cadena" (que, como se sabe, suelen ser los culpables). Lo que trato de evitar es eliminar manualmente cada campo, buscar el ancho del objetivo, etc. Parece que SQL Server podría ahorrarnos mucho tiempo imprimiendo información que presumiblemente ya tiene. – harpo

16

Una manera rápida y sucia de la fijación de estos es para seleccionar las filas en una tabla nueva física, así:

SELECT * INTO dbo.MyNewTable FROM <the rest of the offending query goes here> 

... y luego comparar el esquema de esta tabla en el esquema de la tabla a la que iba previamente INSERT - y busque la (s) columna (s) más grande (s).

+0

Esta es la mejor idea que he escuchado hasta ahora. – harpo

+1

Riesgo de algunos falsos positivos allí. Cuando SSMS define automáticamente el ancho de las columnas, a menudo deja un poco de margen de maniobra. Eso significa que puede ver que algunos se ven como un problema que no es el problema. [Esta respuesta] (http://stackoverflow.com/questions/5143429/identifying-values-which-would-be-trunched-in-an-insert-query) a aproximadamente la misma pregunta reveló esta joya que no tuve t sabe sobre: ​​ 'Select CHARACTER_MAXIMUM_LENGTH dE MyDatabase.INFORMATION_SCHEMA.COLUMNS DONDE TABLE_NAME = 'MyTableName'' – Adamantish

0

Técnicamente, no hay una fila para señalar porque SQL no escribió los datos en la tabla. Normalmente solo capturo el rastro, lo ejecuto el Analizador de consultas (a menos que el problema ya sea obvio por el rastreo, que puede ser en este caso), y depuro rápidamente desde allí con el método antiguo "modificar mi ACTUALIZACIÓN a SELECCIONAR". ¿Realmente no se reduce a una de dos cosas:

a) La definición de su columna es incorrecta, y el ancho debe ser cambiado b) La definición de columna es correcta, y la aplicación debe ser más defensiva

?

1

Recomienda que vote por la solicitud de mejora en el sitio de Microsoft. Ha sido activo desde hace 6 años así que quién sabe si Microsoft va a hacer nunca nada al respecto, pero al menos puede ser una rueda chirriante: Microsoft Connect

2

Soy consciente de que esto es una vieja.Aquí hay un pequeño fragmento de código que uso que ayuda.

Lo que hace esto, es devolver una tabla de las longitudes máximas en la tabla que está tratando de seleccionar. A continuación, puede comparar las longitudes de campo con el máximo devuelto para cada columna y descubrir cuáles causan el problema. Entonces, es solo una consulta simple para limpiar los datos o excluirlos.

DECLARE @col NVARCHAR(50) 
DECLARE @sql NVARCHAR(MAX); 

CREATE TABLE ##temp (colname nvarchar(50), maxVal int) 

DECLARE oloop CURSOR FOR 

SELECT COLUMN_NAME 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'SOURCETABLENAME' AND TABLE_SCHEMA='dbo' 

OPEN oLoop 

    FETCH NEXT FROM oloop INTO @col; 

    WHILE (@@FETCH_STATUS = 0) 
    BEGIN 
     SET @sql = ' 
    DECLARE @val INT; 
    SELECT @val = MAX(LEN(' + @col + ')) FROM dbo.SOURCETABLENAME; 
    INSERT INTO ##temp 
      (colname, maxVal) 
    VALUES (N''' + @col + ''', -- colname - nvarchar(50) 
      @val -- maxVal - int 
      )'; 
     EXEC(@sql); 
     FETCH NEXT FROM oloop INTO @col; 
    END 

    CLOSE oloop; 
    DEALLOCATE oloop 

    SELECT * FROM ##temp 
    DROP TABLE ##temp; 
1

Otra forma aquí es utilizar la búsqueda binaria.

Comenta la mitad de las columnas en tu código y vuelve a intentarlo. Si el error persiste, comente otra mitad de esa mitad y vuelva a intentarlo. Limitará su búsqueda a solo dos columnas al final.

1

Para el truncamiento, se me ocurrió la solución siguiente para encontrar las longitudes máximo de todas las columnas:

1) Seleccione todos los datos en una tabla temporal (nombres de las columnas de suministro cuando sea necesario), por ejemplo,

SELECT col1 
     ,col2 
     ,col3_4 = col3 + '-' + col4 
INTO #temp; 

2) ejecute la siguiente instrucción SQL en la misma conexión (ajustar el nombre de la tabla temporal si es necesario):

DECLARE @table VARCHAR(MAX) = '#temp';  -- change this to your temp table name 

DECLARE @select VARCHAR(MAX) = ''; 
DECLARE @prefix VARCHAR(256) = 'MAX(LEN('; 
DECLARE @suffix VARCHAR(256) = ')) AS max_'; 
DECLARE @nl  CHAR(2)  = CHAR(13) + CHAR(10); 

SELECT @select = @select + @prefix + name + @suffix + name + @nl + ',' 
FROM tempdb.sys.columns 
WHERE object_id = object_id('tempdb..' + @table); 

SELECT @select = 'SELECT ' + @select + '0' + @nl + 'FROM ' + @table 

EXEC(@select); 

devolverá un conjunto de resultados con los nombres de columna con el prefijo 'max_' y muestra la longitud máxima de cada columna.

Una vez que identifica la columna defectuosa, puede ejecutar otras declaraciones de selección para buscar filas extra largas y ajustar su código/datos según sea necesario.

+1

he encontrado este útil incluso para tratar con tipos numéricos. –

0

Lo mejor que funcionó para mí fue poner las filas primero en una tabla temporal usando seleccionar .... en #temptable Luego tomé la longitud máxima de cada columna en esa tabla temporal. p.ej. seleccione max (len (jobid)) como Jobid, .... y luego lo comparó con la definición del campo de la tabla fuente.

Cuestiones relacionadas