Principales respuestas
Problema con decimales en SQL

Pregunta
-
Buenos días a todos:
Estoy llevando el mantenimiento de una aplicación creada en VB 6 que a su vez está vinculada con una base de datos SQL 2005. El caso es que es una aplicación que tiene muchos problemas y está mal desarrollada desde el principio. Paso a comentaros mi problema. Necesitaría, por favor, una sentencia en SQL que me actualizase los valores de una columna con el comando UPDATE.
La columna es varchar (50) pero los datos son todos numéricos y deberían tener dos decimales. Lo que necesito es que me compruebe todos los valores y aquellos que solo tengan un decimal que me añada un 0 para tener dos decimales. O aquellos que no tienen decimales que me añada una coma (no un punto) y dos 0. Y aquellos que ya tengas los dos decimales que no los toque.
Es decir:
Si el valor es 110,1 que lo cambie a 110,10, si es 110 que lo cambie a 110,00 y si es 110,10 que no haga nada.
No puedo ni cambiar el tipo de columna, ni crear una nueva, ni modificar el código en VB... Sólo necesitaría eso.
La tabla se llamaría F_cab y la columna importe_total.
Gracias de antemano y Feliz Año a todos.
Respuestas
-
Siento aguarte la fiesta Willams, la idea es buena, pero eso no va a funcionar. El problema son las comas, Marcales tiene comas como separador de decimales, lo cual quiere decir que esto:
SELECT CAST('9,52' AS DECIMAL(9,2))
Falla con el error:
Msg 8114, Level 16, State 5, Line 1 Error converting data type varchar to numeric.
Pero, en fin, sólo hay que reemplazar la coma por el punto antes de convertirlo a decimal y luego volver a reemplazar el punto por la coma:
UPDATE F_cab SET importe_total = REPLACE(CAST(CAST(REPLACE(importe_total, ',', '.') AS DECIMAL(9,2)) AS VARCHAR), '.', ',')
Jesús López
EntityLite a lightweight, database first, micro orm- Marcado como respuesta Marcales viernes, 2 de enero de 2015 10:13
Todas las respuestas
-
Supongo que lo más sencillo es crear una función de SQL Server que formatee el número a su gusto.
Create Function dbo.fnFormatoNumero(@num varchar(50)) Returns varchar(50) As Begin Declare @pos int; Declare @simboloDecimal char(1); Declare @decimales varchar(50); Declare @numDecimales int; Set @numDecimales = 2; Set @simboloDecimal = ','; Set @pos = CharIndex(@simboloDecimal, @num); If (@pos = 0) Set @num = @num + @simboloDecimal + Replicate('0', @numDecimales); Else If (Len(@num) = @pos) Set @num = @num + Replicate('0', @numDecimales); Else Begin Set @decimales = Substring(@num, @pos + 1, Len(@num) - @pos); If (Len(@decimales > @numDecimales) Raiserror('Cantidad de decimales excede lo esperado', 16, 1); If (Len(@decimales) < @numDecimales) Set @num = @num + Replicate('0', @numDecimales - Len(@decimales)); End Return @num; End
Con la función creada, el UPDATE es sencillo:
Update F_cab Set importe_total = dbo.fnFormatoNumero(@valorAGuardar) Where <clave primaria> = @clavePrimaria;
donde <clave primaria> sería el nombre de la columna que es la clave primaria de la tabla de forma que solamente actualice el registro exacto que busca. Claro que el WHERE es una suposición mía, tal vez usted necesita otro WHERE.
Jose R. MCP
Code Samples -
Hola Marcales,
José, permiteme aportar con una propuesta más simple, por lo menos desde mi punto de vista.
Lo único que se tendría que hacer es lo siguiente
update F_cab set importe_total = cast(importe_total as decimal(9,2));
Lo único que hago es un cast cambiando los valores de texto a decimal(9,2). No discrimino si tiene o no decimales, no importa si está rutina la correrás una sola vez.
Marcales, si deseas probar con un ejemplo antes de ejecutar lo propuesto te dejo el script que hice
create table decimales (monto varchar(50)) insert into decimales values ('100'), ('200.1'), ('300.20'), ('400.560'); update decimales set monto = cast(monto as decimal(9,2)); select * from decimales;
Y este el resultado del select
-----------------------------------------------------------------------------------------------------
Espero haberte ayudado con mi sugerencia, si resolvió tu problema no olvides marcarla como respuesta.
Willams Morales P.
Arequipa - Perú
- Editado Willams Morales miércoles, 31 de diciembre de 2014 17:08
- Propuesto como respuesta webJose miércoles, 31 de diciembre de 2014 17:09
-
Ha! Excelente williams. No lo pensé. Hago mucho SQL pero nunca me molesto en usar los tipos de dato con precision y scale. Siempre uso los tipos "estándar". Ni por fuera de la frente me pasó pensar en algo así. Buenísimo.
EDICIÓN: Un detalle nada más: El CAST() a decimal(9, 2) podría significar la pérdida de información si tiene más de 2 decimales. Lo hago notar en caso de que esto le sea importante.
Jose R. MCP
Code Samples
- Editado webJose miércoles, 31 de diciembre de 2014 17:11
-
-
Siento aguarte la fiesta Willams, la idea es buena, pero eso no va a funcionar. El problema son las comas, Marcales tiene comas como separador de decimales, lo cual quiere decir que esto:
SELECT CAST('9,52' AS DECIMAL(9,2))
Falla con el error:
Msg 8114, Level 16, State 5, Line 1 Error converting data type varchar to numeric.
Pero, en fin, sólo hay que reemplazar la coma por el punto antes de convertirlo a decimal y luego volver a reemplazar el punto por la coma:
UPDATE F_cab SET importe_total = REPLACE(CAST(CAST(REPLACE(importe_total, ',', '.') AS DECIMAL(9,2)) AS VARCHAR), '.', ',')
Jesús López
EntityLite a lightweight, database first, micro orm- Marcado como respuesta Marcales viernes, 2 de enero de 2015 10:13
-
-