none
Problema con decimales en SQL RRS feed

  • 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.

    miércoles, 31 de diciembre de 2014 12:20

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
    jueves, 1 de enero de 2015 10:23

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

    miércoles, 31 de diciembre de 2014 14:06
  • 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
    miércoles, 31 de diciembre de 2014 17:07
  • 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
    miércoles, 31 de diciembre de 2014 17:09
  • Muchas gracias a todos por responder. El viernes probaré las soluciones que me dais y os digo que tal me fué.

    Nuevamente gracias y Feliz 2015.

    Saludos

    miércoles, 31 de diciembre de 2014 22:50
  • 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
    jueves, 1 de enero de 2015 10:23
  • Cierto. Gracias por la observación Jesús.
    jueves, 1 de enero de 2015 17:45
  • Muchas gracias... He probado la sentencia que ha escrito Jesús y me va perfecto. Era eso justo lo que yo intentaba reproducir.

    Sois unos máquinas.

    Saludos y gracias.

    viernes, 2 de enero de 2015 10:13