Evitando errores de conversión de datos TSQL
-
03-07-2019 - |
Pregunta
Creo que lo mejor es pedirlo en forma de un ejemplo simple. La siguiente parte de SQL provoca un " DB-Library Error: 20049 Gravedad: 4 Mensaje: la conversión de datos generó un mensaje de desbordamiento " , pero ¿por qué?
declare @a numeric(18,6), @b numeric(18,6), @c numeric(18,6)
select @a = 1.000000, @b = 1.000000, @c = 1.000000
select @a/(@b/@c)
go
¿Cómo es esto diferente a:
select 1.000000/(1.000000/1.000000)
go
que funciona bien?
Solución
Me encontré con el mismo problema la última vez que intenté usar Sybase (hace muchos años). Partiendo de la mentalidad de SQL Server, no me di cuenta de que Sybase intentaría forzar a los decimales, lo que, matemáticamente, es lo que debería hacer. :)
De la Sybase manual :
Los errores de desbordamiento aritmético ocurren cuando el nuevo tipo tiene muy pocos decimales lugares para acomodar los resultados.
Y más abajo:
Durante conversiones implícitas a numéricas o tipos decimales, pérdida de escala genera un error de escala. Utilizar el Arithabort numeric_truncation opción para determinar qué tan grave es tal error se considera. La configuración por defecto, arithabort numeric_truncation en, aborta la declaración que causa la error pero sigue procesando otra declaraciones en la transacción o lote. Si pones arithabort Numeric_truncation off, Adaptive El servidor trunca los resultados de la consulta y continúa el procesamiento.
Entonces, suponiendo que la pérdida de precisión es aceptable en su escenario , es probable que desee lo siguiente al comienzo de su transacción:
SET ARITHABORT NUMERIC_TRUNCATION OFF
Y luego al final de su transacción:
SET ARITHABORT NUMERIC_TRUNCATION ON
Esto es lo que me lo resolvió hace muchos años ...
Otros consejos
Esto es solo una especulación, pero ¿podría ser que el DBMS no vea el valor dinámico de sus variables sino solo los valores potenciales? Por lo tanto, un número de seis decimal dividido por un número de seis decimal podría resultar en un número de doce decimal; en la división literal, el DBMS sabe que no hay desbordamiento. Sin embargo, aún no estoy seguro de por qué le importaría al DBMS, ¿no debería devolver el resultado de dos divisiones de seis decimales con un número de 18 decimales?
Debido a que ha declarado las variables en el primer ejemplo, se espera que el resultado sea de la misma declaración (es decir, numérico (18,6)) pero no lo es.
Tengo que decir que el primero funcionó en SQL2005 (devolvió 1.000000 [el mismo tipo declarado]), mientras que el segundo regresó (1.000000000000000000000 [Una declaración totalmente diferente]).
No está directamente relacionado, pero podría ahorrarle a alguien algún tiempo con los errores de desbordamiento aritmético utilizando Sybase ASE (12.5.0.3).
Estaba configurando algunos valores predeterminados en una tabla temporal que intenté actualizar más adelante, y me topé con un error de desbordamiento aritmético.
declare @a numeric(6,3)
select 0.000 as thenumber into #test --indirect declare
select @a = ( select thenumber + 100 from #test )
update #test set thenumber = @a
select * from #test
Muestra el error:
Arithmetic overflow during implicit conversion of NUMERIC value '100.000' to a NUMERIC field .
Lo que en mi cabeza debería funcionar, pero no funciona como la columna 'thenumber' no se declaró (o se declaró indirectamente como decimal (4,3)). Por lo tanto, tendría que declarar indirectamente la columna de la tabla temporal con la escala y la precisión al formato que desee, como en mi caso fue 000.000.
select 000.000 as thenumber into #test --this solved it
Esperemos que le ahorre tiempo a alguien :)