Eliminar ceros finales de decimal en SQL Server


85

Tengo una columna, DECIMAL(9,6)es decir, admite valores como 999,123456.

Pero cuando inserto datos como 123,4567 se convierte en 123,456700

¿Cómo eliminar esos ceros?


Cambie la respuesta correcta a la respuesta de @ Andomar
dangalg

@dangalg: Creo firmemente que esto debería hacerse en la capa de presentación. Por eso nunca cambié la respuesta aceptada. Sin embargo, después de más consideraciones, creo que debería aceptar lo que la comunidad indicó claramente, cuál es la mejor respuesta.
abatishchev

Respuestas:


147

A decimal(9,6)almacena 6 dígitos en el lado derecho de la coma. Mostrar ceros finales o no es una decisión de formato, generalmente implementada en el lado del cliente.

Pero dado que SSMS formatea floatsin ceros finales, puede eliminar ceros finales al convertir el decimala a float:

select 
    cast(123.4567 as DECIMAL(9,6))
,   cast(cast(123.4567 as DECIMAL(9,6)) as float)

huellas dactilares:

123.456700  123,4567

(Mi separador decimal es una coma, pero SSMS formatea decimal con un punto. Aparentemente un problema conocido ).


8
+1 Pensé que la conversión a flotar introduciría cierta imprecisión en los resultados, pero parece funcionar absolutamente bien.
Martin Smith

1
Una desventaja de este método es que si comienza con "2.0" lo convertirá en "2". Probablemente esto esté bien para la persona que hace la pregunta, pero necesitaba poder mantener un solo cero después del decimal, sin mantener otros ceros finales. La respuesta de @ user1959416 resuelve eso.
Mason G. Zhwiti

6
Además, la flotación en general es una mala elección para almacenar números. Obtendrá errores de redondeo ya que no es un tipo exacto. Nunca use flotador.
HLGEM

El comentario sobre el formato de los flotadores sin ceros finales fue extremadamente útil
Sanjiv Jivan

Sin embargo, ¿estoy en lo correcto al pensar que la escala y la precisión de un decimal pueden exceder la de un flotante y, por lo tanto, puede haber casos en los que (con un valor significativo de más de 17 dígitos) esta respuesta no funcione?
Caius Jard

31

Puede utilizar la FORMAT()función (SqlAzure y Sql Server 2012+):

SELECT FORMAT(CAST(15.12     AS DECIMAL(9,6)), 'g18')  -- '15.12'
SELECT FORMAT(CAST(0.0001575 AS DECIMAL(9,6)), 'g10')  -- '0.000158'
SELECT FORMAT(CAST(2.0       AS DECIMAL(9,6)), 'g15')  -- '2'

Tenga cuidado al usar con FLOAT (o REAL): no use g17o más grande ( g8o más grande con REAL), porque la precisión limitada de la representación de la máquina causa efectos no deseados:

SELECT FORMAT(CAST(15.12 AS FLOAT), 'g17')         -- '15.119999999999999'
SELECT FORMAT(CAST(0.9 AS REAL), 'g8')             -- '0.89999998'
SELECT FORMAT(CAST(0.9 AS REAL), 'g7')             -- '0.9'

Además, tenga en cuenta que, según la documentación :

FORMAT se basa en la presencia de .NET Framework Common Language Runtime (CLR). Esta función no será remota ya que depende de la presencia del CLR. La comunicación remota de una función que requiere CLR provocaría un error en el servidor remoto.

También funciona en SqlAzure.


Para mis propósitos, encontré una cadena de formato de g8 formateada mi número como "1e-08" que no era lo que buscaba. Sin embargo, esta respuesta me llevó a una que podría usar
Caius Jard

17
SELECT CONVERT(DOUBLE PRECISION, [ColumnName])

SQL Server 2008 y superior
Bat_Programmer

¿Qué sucede cuando el número es como "123.10705000000"? Intenté con SELECT CONVERT (DOBLE PRECISIÓN, 123.10705000000) pero me da "123.107" como respuesta. y quiero "123.10705" como salida? ¿Hay alguna manera? No quiero usar CHARINDEX.
Bhavika Zimbar

16

Estaba reacio a lanzar para flotar debido a la posibilidad de que haya más dígitos en mi decimal de los que flota puede representar

FORMAT cuando se usa con una cadena de formato .net estándar 'g8' devuelve la notación científica en casos de decimales muy pequeños (por ejemplo, 1e-08) que tampoco era adecuada

El uso de una cadena de formato personalizado ( https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings ) me permitió lograr lo que quería:

DECLARE @n DECIMAL(9,6) =1.23;
SELECT @n
--> 1.230000
SELECT FORMAT(@n, '0.######')
--> 1.23

Si desea que su número tenga al menos un cero al final, de modo que 2.0 no se convierta en 2, use una cadena de formato como 0.0#####

El punto decimal está localizado, por lo que las culturas que usan una coma como separador decimal encontrarán una salida de coma donde el. es

Por supuesto, esta es la práctica desalentadora de tener la capa de datos formateando (pero en mi caso no hay otra capa; el usuario está literalmente ejecutando un procedimiento almacenado y poniendo el resultado en un correo electrónico: /)


6
SELECT REVERSE(ROUND(REVERSE(2.5500),1))

huellas dactilares:

2.55

2
Este método es bueno porque dejará un cero final si solo hay un cero. Entonces, 2.5500 devuelve 2.55 y 2.000 devuelve 2.0 en lugar de 2. Excelente para cuando está formateando tamaños de motor en un vehículo ...
Mason G. Zhwiti

4
@ MasonG.Zhwiti Tengo dudas de que esto funcione con algunos decimales con más dígitos después del punto decimal como 232.33220003200, por ejemplo: -)
gotqn

@gotqn Buen punto, eso definitivamente falla. Sin embargo, para nuestro caso de uso específico (formateo de tamaños de motor en automóviles), funciona perfectamente. :)
Mason G. Zhwiti

como dijo @gotqn ... tiene errores cuando el número es largo
Ofear

Esto no funciona exactamente para números como 0.56000. rendirá 56. Gracioso
Gunjan Shakya


3

Prueba esto :

SELECT REPLACE(TRIM(REPLACE(20.5500, "0", " ")), " ", "0")

Da 20,55


1
REPLACE (TRIM (REPLACE (20.00, "0", "")), "", "0") te deja con un final. => "20."
Keith Sirmons

Es perfectamente aplicable a mi caso y parece ser la solución más sencilla. ¡Pulgar y votar!
Oak_3260548

¡Gran solución sin tener que convertir a flotar! se 0.000convirtió en un problema menor detectado .. aquí está la solución SELECT REPLACE(RTRIM(REPLACE(20.5500, "0", " ")), " ", "0")para recortar solo los ceros finales
wilson

2

Tuve un problema similar, pero también se me pidió que eliminara el punto decimal donde no había decimal, aquí estaba mi solución que divide el decimal en sus componentes y basa el número de caracteres que toma de la cadena del punto decimal en la longitud de el componente de fracción (sin usar CASE). Para hacer las cosas aún más interesantes, mi número se almacenó como un flotador sin sus decimales.

DECLARE @MyNum FLOAT
SET @MyNum = 700000
SELECT CAST(PARSENAME(CONVERT(NUMERIC(15,2),@MyNum/10000),2) AS VARCHAR(10)) 
+ SUBSTRING('.',1,LEN(REPLACE(RTRIM(REPLACE(CAST(PARSENAME(CONVERT(NUMERIC(15,2),@MyNum/10000),1) AS VARCHAR(2)),'0',' ')),' ','0'))) 
+ REPLACE(RTRIM(REPLACE(CAST(PARSENAME(CONVERT(NUMERIC(15,2),@MyNum/10000),1) AS VARCHAR(2)),'0',' ')),' ','0') 

El resultado es doloroso, lo sé, pero llegué allí, con mucha ayuda de las respuestas anteriores.


2

La mejor manera es NO convertir a FLOAT o MONEY antes de convertir debido a la posibilidad de pérdida de precisión. Entonces, las formas seguras pueden ser algo como esto:

CREATE FUNCTION [dbo].[fn_ConvertToString]
(
    @value sql_variant
)
RETURNS varchar(max)
AS
BEGIN
    declare @x varchar(max)
    set @x= reverse(replace(ltrim(reverse(replace(convert(varchar(max) , @value),'0',' '))),' ',0))

    --remove "unneeded "dot" if any
    set @x = Replace(RTRIM(Replace(@x,'.',' ')),' ' ,'.')
    return @x
END

donde @value puede ser cualquier decimal (x, y)


@abatishchev, fn_ es un prefijo preferido para funciones sql, los prefijos se utilizan en la codificación estándar y la convención de nomenclatura, así como en las mejores prácticas, podemos personalizar nuestros prefijos, pero para las mejores prácticas que utilizamos sp_para procedimientos almacenados, fn_funciones, tbltablas, etc. en ... esto no es un requisito, pero son las mejores prácticas para organizar nuestras bases de datos.
japzdivino

@japongskie: lo siento, pero no. No hay necesidad de prefijos en absoluto. En realidad, esta es la peor práctica. Consulte msdn.microsoft.com/en-us/library/dd172115(v=vs.100).aspx sqlperformance.com/2012/10/t-sql-queries/sp_prefix dba.stackexchange.com/q/25348/3186 y muchos más
abatishchev

@abatishchev, oh ya veo ... así que ya no seguiré la enseñanza de la escuela ... jaja LOL, ya que su enlace vino de mdsn, gracias por este, cambiaré ahora mi mejor práctica .. :)
japzdivino

2

Tuve un problema similar, necesitaba recortar los ceros finales de números como xx0000,x00000,xxx000

Solía:

select LEFT(code,LEN(code)+1 - PATINDEX('%[1-Z]%',REVERSE(code))) from Tablename

Código es el nombre del campo con el número que se va a recortar. Espero que esto ayude a alguien más.


Este comentario funciona bien cuando está utilizando una versión de SQL Server que es lo suficientemente antigua como para no poder usar las funciones de compilación TRIM o FORMAT en SQL Server.
David Parvin

Encontré un problema con esta respuesta. Si el valor en el campo 'código' es algo así como '10', devolverá '1'. Si el número es '10 .00 ', creo que también ignora el punto decimal.
David Parvin

1

Otra opción...

No sé qué tan eficiente es esto, pero parece funcionar y no pasa por flotación:

select replace(rtrim(replace(
       replace(rtrim(replace(cast(@value as varchar(40)), '0', ' ')), ' ', '0')
       , '.', ' ')), ' ', '.')

La línea media elimina los espacios finales, los dos exteriores eliminan el punto si no hay dígitos decimales


1

Que necesitaba para eliminar los ceros finales en mis decimales por lo que podría generar una cadena de una cierta longitud, con sólo conducen ceros

(por ejemplo, necesitaba generar 14 caracteres para que 142.023400 se convirtiera en 000000142.0234),

Usé parsename, reversey cast as intpara eliminar los ceros finales:

SELECT
    PARSENAME(2.5500,2)
    + '.'
    + REVERSE(CAST(REVERSE(PARSENAME(2.5500,1)) as int))

(Para luego obtener mis ceros iniciales, podría replicar el número correcto de ceros en función de la longitud de lo anterior y concatenar esto al frente de lo anterior)

Espero que esto ayude a alguien.


@Protiguous Dado que hay 1 punto decimal, 2.5500 se lee como <schema_name>. <object_name>. El segundo parámetro de 2 devuelve el nombre del esquema, el segundo parámetro de 1 devuelve el nombre del objeto. Por lo general, se usaría como PARSENAME ('dbo.TableName', 2) para devolver dbo o PARSENAME ('dbo.TableName', 1) para devolver TableName.
Ali

Hola ... Veo que mi alias está marcado en tu comentario. ¿No se por que?
Protiguous

La pregunta exacta que me hiciste el 26 de mayo de 2020 fue "¿Cómo se supone que funciona PARSENAME aquí?" Lamento que haya tardado tanto en responderte.
Ali

1

es posible eliminar los ceros iniciales y finales en TSQL

  1. Conviértalo en una cadena usando la función STR TSQL si no es una cadena, entonces

  2. Quitar ceros iniciales y finales

    SELECT REPLACE(RTRIM(LTRIM(REPLACE(AccNo,'0',' '))),' ','0') AccNo FROM @BankAccount
    
  3. Más información en el foro .


4
Un poco feo, pero esta versión mata las sobras '.':REPLACE(RTRIM(REPLACE(REPLACE(RTRIM(REPLACE(X,'0',' ')),' ','0'),'.',' ')),' ','.')
Chris B

1
Tenga cuidado, si el número no es decimal, también recortará los ceros. CHARINDEX ('.', @ Number)! = 1 lo probará.
Muflix

Mi verificación decimal anterior es incorrecta. Aquí es mejor: Seleccione Len (@Test) - Len (Reemplazar (@Test, 'a', '')) Como se explica NumberOfCharacters: tinyurl.com/o4fc8g7 y tinyurl.com/kgzkuqk
Muflix

0

¿Qué tal esto? Suponiendo que los datos que ingresan a su función son @thisData:

BEGIN
  DECLARE @thisText VARCHAR(255)
  SET @thisText = REPLACE(RTRIM(REPLACE(@thisData, '0', ' ')), ' ', '0')
  IF SUBSTRING(@thisText, LEN(@thisText), 1) = '.'
    RETURN STUFF(@thisText, LEN(@thisText), 1, '')
  RETURN @thisText
END

0
case when left(replace(ltrim(rtrim(replace(str(XXX, 38, 10), '0',  ' '))), ' ', '0'), 1) = '.'
then '0' 
else ''
end +

replace(ltrim(rtrim(replace(str(XXX, 38, 10), '0',  ' '))), ' ', '0') +

case when right(replace(ltrim(rtrim(replace(str(XXX, 38, 10), '0',  ' '))), ' ', '0'), 1) = '.'
then '0' 
else ''
end

¿No reemplazaría esto también a los 0 (ceros) entre los números? No creas que reemplazar solo funciona en los extremos ...
mtk

0

Entiendo que esta es una publicación antigua, pero me gustaría proporcionar SQL que se me ocurrió

DECLARE @value DECIMAL(23,3)
set @value = 1.2000
select @value original_val, 
    SUBSTRING(  CAST( @value as VARCHAR(100)), 
                0,
                PATINDEX('%.%',CAST(@value as VARCHAR(100)))
            )
      + CASE WHEN ROUND( 
                        REVERSE( SUBSTRING( CAST(@value as VARCHAR(100)),
                                        PATINDEX('%.%',CAST(@value as VARCHAR(100)))+1,
                                        LEN(CAST(@value as VARCHAR(100)))
                                        )
                                )
                    ,1) > 0 THEN 
            '.' 
            +  REVERSE(ROUND(REVERSE(SUBSTRING( CAST(@value as VARCHAR(100)),
                                                PATINDEX('%.%',CAST(@value as VARCHAR(100)))+1,
                                                LEN(CAST(@value as VARCHAR(100)))
                                                )
                ),1))
        ELSE '' END  AS modified_val

0

prueba esto.

select CAST(123.456700 as float),cast(cast(123.4567 as DECIMAL(9,6)) as float)

0

La forma más sencilla es CAST el valor como FLOAT y luego a un tipo de datos de cadena.

CAST(CAST(123.456000 AS FLOAT) AS VARCHAR(100))

-1

Prueba esto:

select Cast( Cast( (ROUND( 35.457514 , 2) *100) as Int) as float ) /100

Prefiero la respuesta de @ user1959416 mejor aquí, ya que no cambia los valores. Por ejemplo, comenzando con 2.5550, su método da como resultado 2.56, mientras que el de ellos devuelve 2.555.
Mason G. Zhwiti

-1

Sé que este hilo es muy antiguo, pero para aquellos que no usan SQL Server 2012 o superior o no pueden usar la función FORMAT por algún motivo, lo siguiente funciona.

Además, muchas de las soluciones no funcionaron si el número era menor que 1 (por ejemplo, 0.01230000).

Tenga en cuenta que lo siguiente no funciona con números negativos.

DECLARE @num decimal(28,14) = 10.012345000
SELECT PARSENAME(@num,2) + REPLACE(RTRIM(LTRIM(REPLACE(@num-PARSENAME(@num,2),'0',' '))),' ','0') 

set @num = 0.0123450000
SELECT PARSENAME(@num,2) + REPLACE(RTRIM(LTRIM(REPLACE(@num-PARSENAME(@num,2),'0',' '))),' ','0') 

Devuelve 10.012345 y 0.012345 respectivamente.


-1

Prueba esto:

select isnull(cast(floor(replace(rtrim(ltrim('999,999.0000')),',','')) as int),0)

este regresa 999999, el OP solicita eliminar los ceros finales.
japzdivino

-1

Una columna DECIMAL (9,6) se convertirá en flotante sin pérdida de precisión, por lo que CAST (... AS float) funcionará.


@HLGEM: decir que flotar es una mala elección para almacenar números y que "Nunca usar flotador" no es correcto; solo tiene que conocer sus números, por ejemplo, las mediciones de temperatura irían bien como flotadores.

@abatishchev y @japongskie: los prefijos delante de los procesos y funciones almacenados en SQL siguen siendo una buena idea, si no son necesarios; los enlaces que mencionaste solo indican que no uses el prefijo "sp_" para los procedimientos almacenados que no debes usar, otros prefijos están bien, por ejemplo, "usp_" o "spBob_"

Referencia: "Todos los números enteros con 6 o menos dígitos decimales significativos se pueden convertir a un valor de punto flotante IEEE 754 sin pérdida de precisión": https://en.wikipedia.org/wiki/Single-precision_floating-point_format

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.