SQl: Error calculando

11/07/2005 - 12:11 por raul.fenollar | Informe spam
Abajo he puesto un ejemplo de unos cálculos de SQL, que cambian si se
realizan todos en una única línea de código, o se realizan en varios pasos:

Lo primero que he puesto ha sido una operación base, con las constantes que
se usan para el cálculo de forma que nos sirva de Ejemplo:

y despúes he puesto el cálculo con variables, viendo que si el cálculo se
realiza todo de golpe, el resultado no es correcto, pero que si lo
realizamos por partes si que funciona bien, con la salvedad del número de
decimales que saca, ya que a pesar de ser todas las variables utilizadas
decimal(28,6), ni saca 6 decimales, ni saca como la primera operación todos
los deimales, si no que se lo monta para sacar 10...

- Me gustaria saber si esto estaba documentado, y hasta que punto es normal
el tema de los decimales en la división.


Muchas gracias a todos.

José Raúl Fenollar Martínez
Gandia (Valencia)


SELECT
Cálculo_1_A_6_Decimales=convert(decimal(28,6),(6000.000000+((12.300000+0.000000)*10.000000)+0.000000+0.000000)/210.000000),
Cálculo_1_A_X_Decimales=(6000.000000+((12.300000+0.000000)*10.000000)+0.000000+0.000000)/210.000000


DECLARE
@1 DECIMAL(28,6),
@2 DECIMAL(28,6),
@3 DECIMAL(28,6),
@4 DECIMAL(28,6),
@5 DECIMAL(28,6),
@6 DECIMAL(28,6),
@7 DECIMAL(28,6),
@8 DECIMAL(28,6),
@9 DECIMAL(28,6),
@10 DECIMAL(28,6)

SELECT
@1`00,
@2.3,
@3=0,
@4,
@5=0,
@6=0,
@7!0

SELECT
Cálculo_2_A_6_Decimales=convert(decimal(28,6),(@1+((@2+@3)*@4)+@5+@6)/@7),
Cálculo_2_A_X_Decimales=(@1+((@2+@3)*@4)+@5+@6)/@7


SELECT
@8=(@2+@3)*@4

SELECT
@9=@1+@8

SELECT
@10=@9+@5+@6

SELECT Cálculo_3_A_6_Decimales=convert(decimal(28,6),@10/@7),
Cálculo_3_A_X_Decimales=@10/@7

Preguntas similare

Leer las respuestas

#6 Alejandro Mesa
12/07/2005 - 16:58 | Informe spam
Raul,

Ahora entiendo porque salen los resultados así. Pero lo que también es
cierto, es que SQL nos puede llevar a errar en los cálculos, si hacemos una
mala elección de variables, o una mala agrupación de las mismas al calcular
porque al cambiar la precisión y la escala al hacer una operación
(Multiplicar,sumar,dividir), puede cambiar los resultados finales.



Lo que dices es muy cierto. Debemos ser cuidadosos al seleccionar la
precision y escala. Por ejemplo, en el script que posteastes, yo cambie la
(p,s) de acuerdo a los valores usados.

Ejemplo:

use tempdb
go

DECLARE
@1 DECIMAL(12, 4),
@2 DECIMAL(12, 4),
@3 DECIMAL(12, 4),
@4 DECIMAL(12, 4),
@5 DECIMAL(12, 4),
@6 DECIMAL(12, 4),
@7 DECIMAL(12, 4),
@8 DECIMAL(12, 4),
@9 DECIMAL(12, 4),
@10 DECIMAL(12, 4)

SELECT
@1`00.00,
@2.30,
@3=0.00,
@4.00,
@5=0.00,
@6=0.00,
@7!0.00


SELECT
Cálculo_2_A_6_Decimales=convert(decimal(28,6),(@1+((@2+@3)*@4)+@5+@6)/@7),
Cálculo_2_A_X_Decimales=(@1+((@2+@3)*@4)+@5+@6)/@7,
prec_formula = cast(substring(cast((@1+((@2+@3)*@4)+@5+@6)/@7 as
varbinary),1,1) as tinyint),
scale_formula = cast(substring(cast((@1+((@2+@3)*@4)+@5+@6)/@7 as
varbinary),2,1) as tinyint)
go


AMB

"raul.fenollar" wrote:

Extarordinaria la explicación... muchas gracias.

Ahora entiendo porque salen los resultados así. Pero lo que también es
cierto, es que SQL nos puede llevar a errar en los cálculos, si hacemos una
mala elección de variables, o una mala agrupación de las mismas al calcular
porque al cambiar la precisión y la escala al hacer una operación
(Multiplicar,sumar,dividir), puede cambiar los resultados finales.

Mira a ver si esto te parece correcto. Alejandro.

Variación del ejemplo:
29,157142857142857142857142857143 que redondeado es 29,157143 y es el
resultado buscado.
en teoria existan más decimales y la formula deberia dar el resultado
correcto.
y escala 6, y saca el resultado 29,157142, sin estar redondeado a un 3 final


DECLARE
@1 DECIMAL(28,10),
@2 DECIMAL(28,10),
@3 DECIMAL(28,10),
@4 DECIMAL(28,10),
@5 DECIMAL(28,10),
@6 DECIMAL(28,10),
@7 DECIMAL(28,10),
@8 DECIMAL(28,10),
@9 DECIMAL(28,10),
@10 DECIMAL(28,10)

SELECT
@1`00,
@2.3,
@3=0,
@4,
@5=0,
@6=0,
@7!0


SELECT
Cálculo_2_A_6_Decimales=convert(decimal(28,6),(@1+((@2+@3)*@4)+@5+@6)/@7),
Cálculo_2_A_X_Decimales=(@1+((@2+@3)*@4)+@5+@6)/@7,
prec_formula = cast(substring(cast((@1+((@2+@3)*@4)+@5+@6)/@7 as
varbinary),1,1) as tinyint),
scale_formula = cast(substring(cast((@1+((@2+@3)*@4)+@5+@6)/@7 as
varbinary),2,1) as tinyint)




"Alejandro Mesa" escribió en el
mensaje news:
> Raul,
>
> Deja ver como te explico lo que esta pasando. Si lees en los libros en
> linea
> sobre el tema "Precision, Scale, and Length", veras que la precision y
> escala
> del resultado de una expression que involucra tipos decimales o numericos,
> esta basada en la precision y escala de los operandos y definida por
> formulas
> que aparecen en una tabla. En tu primer ejemplo:
>
>> SELECT
>> Cálculo_1_A_6_Decimales=convert(decimal(28,6),(6000.000000+((12.300000+0.000000)*10.000000)+0.000000+0.000000)/210.000000),
>>
>> Cálculo_1_A_X_Decimales=(6000.000000+((12.300000+0.000000)*10.000000)+0.000000+0.000000)/210.000000
>
> el resultado tendra una precision de 37 y una escala de 22, lo cual al
> convertir a decimal(28, 6), debe ser redondeado. En este script veras a lo
> que me refiero, y tambien veras como saber la precision y escala del
> resultado (Gracias a Steve Kass http://www.users.drew.edu/skass/ , que fue
> quien me enseño como hacerlo).
>
> declare @v sql_variant
>
> set @v > > (6000.000000+((12.300000+0.000000)*10.000000)+0.000000+0.000000)/210.000000
>
> select
> (6000.000000+((12.300000+0.000000)*10.000000)+0.000000+0.000000)/210.000000
> as c1,
> sql_variant_property(@v, 'BaseType'),
> cast(substring(cast(@v as varbinary),1,1) as tinyint) as prec,
> cast(substring(cast(@v as varbinary),2,1) as tinyint) as scale,
> cast((6000.000000+((12.300000+0.000000)*10.000000)+0.000000+0.000000)/210.000000
> as decimal(28, 6)) as c2
> go
>
> En tu segundo ejemplo:
>
>> DECLARE
>> @1 DECIMAL(28,6),
>> @2 DECIMAL(28,6),
>> @3 DECIMAL(28,6),
>> @4 DECIMAL(28,6),
>> @5 DECIMAL(28,6),
>> @6 DECIMAL(28,6),
>> @7 DECIMAL(28,6),
>> @8 DECIMAL(28,6),
>> @9 DECIMAL(28,6),
>> @10 DECIMAL(28,6)
>>
>> SELECT
>> @1`00,
>> @2.3,
>> @3=0,
>> @4,
>> @5=0,
>> @6=0,
>> @7!0
>>
>> SELECT
>> Cálculo_2_A_6_Decimales=convert(decimal(28,6),(@1+((@2+@3)*@4)+@5+@6)/@7),
>> Cálculo_2_A_X_Decimales=(@1+((@2+@3)*@4)+@5+@6)/@7
>
> la precision y escala del resultado es (38, 6), por lo que la escala del
> resultado y la de la conversion son la misma y por lo tanto no hace falta
> redondear el resultado.
>
> En el tercer ejemplo:
>
>> ???
>> SELECT
>> @8=(@2+@3)*@4
>>
>> SELECT
>> @9=@1+@8
>>
>> SELECT
>> @10=@9+@5+@6
>>
>> SELECT Cálculo_3_A_6_Decimales=convert(decimal(28,6),@10/@7),
>> Cálculo_3_A_X_Decimales=@10/@7
>
> La formula @10 / @7, definen la precision del resultado final que es (38,
> 10), y cuyo valor es 29.1571428571, el cual al ser convertido a
> decimal(28,
> 6) debe ser redondeado.
>
> DECLARE
> @1 DECIMAL(28,6),
> @2 DECIMAL(28,6),
> @3 DECIMAL(28,6),
> @4 DECIMAL(28,6),
> @5 DECIMAL(28,6),
> @6 DECIMAL(28,6),
> @7 DECIMAL(28,6),
> @8 DECIMAL(28,6),
> @9 DECIMAL(28,6),
> @10 DECIMAL(28,6)
>
> SELECT
> @1`00,
> @2.3,
> @3=0,
> @4,
> @5=0,
> @6=0,
> @7!0
>
> set @8 =(@2 + @3)* @4
> set @9 = @1 + @8
> set @10 = @9 + @5 + @6
>
> select
> cast(substring(cast(@8 as varbinary),1,1) as tinyint) as prec_var_8,
> cast(substring(cast(@8 as varbinary),2,1) as tinyint) as scale_var_8,
> cast(substring(cast((@2 + @3)* @4 as varbinary),1,1) as tinyint) as
> prec_formula_var_8,
> cast(substring(cast((@2 + @3)* @4 as varbinary),2,1) as tinyint) as
> scale_formula_var_8,
> (@2 + @3)* @4 as formula_var_8,
> cast(substring(cast(@9 as varbinary),1,1) as tinyint) as prec_var_9,
> cast(substring(cast(@9 as varbinary),2,1) as tinyint) as scale_var_9,
> cast(substring(cast(@1 + @8 as varbinary),1,1) as tinyint) as
> prec_formula_var_9,
> cast(substring(cast(@1 + @8 as varbinary),2,1) as tinyint) as
> scale_formula_var_9,
> @1 + @8 as formula_var_9,
> @10 / @7 as c1,
> cast(substring(cast(@10 / @7 as varbinary),1,1) as tinyint) as
> prec_formula_final,
> cast(substring(cast(@10 / @7 as varbinary),2,1) as tinyint) as
> scale_formula_final,
> @10 / @7 as formula_final,
> cast(@10 / @7 as decimal(28, 6)) as c2
> go
>
>
> Saludos,
>
> AMB
>
> "raul.fenollar" wrote:
>
>> Abajo he puesto un ejemplo de unos cálculos de SQL, que cambian si se
>> realizan todos en una única línea de código, o se realizan en varios
>> pasos:
>>
>> Lo primero que he puesto ha sido una operación base, con las constantes
>> que
>> se usan para el cálculo de forma que nos sirva de Ejemplo:
>>
>> y despúes he puesto el cálculo con variables, viendo que si el cálculo se
>> realiza todo de golpe, el resultado no es correcto, pero que si lo
>> realizamos por partes si que funciona bien, con la salvedad del número de
>> decimales que saca, ya que a pesar de ser todas las variables utilizadas
>> decimal(28,6), ni saca 6 decimales, ni saca como la primera operación
>> todos
>> los deimales, si no que se lo monta para sacar 10...
>>
>> - Me gustaria saber si esto estaba documentado, y hasta que punto es
>> normal
>> el tema de los decimales en la división.
>>
>>
>> Muchas gracias a todos.
>>
>> José Raúl Fenollar Martínez
>> Gandia (Valencia)
>>
>>
>> SELECT
>> Cálculo_1_A_6_Decimales=convert(decimal(28,6),(6000.000000+((12.300000+0.000000)*10.000000)+0.000000+0.000000)/210.000000),
>>
>> Cálculo_1_A_X_Decimales=(6000.000000+((12.300000+0.000000)*10.000000)+0.000000+0.000000)/210.000000
>>
>>
>> DECLARE
>> @1 DECIMAL(28,6),
>> @2 DECIMAL(28,6),
>> @3 DECIMAL(28,6),
>> @4 DECIMAL(28,6),
>> @5 DECIMAL(28,6),
>> @6 DECIMAL(28,6),
>> @7 DECIMAL(28,6),
>> @8 DECIMAL(28,6),
>> @9 DECIMAL(28,6),
>> @10 DECIMAL(28,6)
>>
>> SELECT
>> @1`00,
>> @2.3,
>> @3=0,
>> @4,
>> @5=0,
>> @6=0,
>> @7!0
>>
>> SELECT
>> Cálculo_2_A_6_Decimales=convert(decimal(28,6),(@1+((@2+@3)*@4)+@5+@6)/@7),
>> Cálculo_2_A_X_Decimales=(@1+((@2+@3)*@4)+@5+@6)/@7
>>
>>
>> ???
>> SELECT
>> @8=(@2+@3)*@4
>>
>> SELECT
>> @9=@1+@8
>>
>> SELECT
>> @10=@9+@5+@6
>>
>> SELECT Cálculo_3_A_6_Decimales=convert(decimal(28,6),@10/@7),
>> Cálculo_3_A_X_Decimales=@10/@7
>>
>>
>>
>>



email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una pregunta AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida