Удаление конечных нулей из decimal в SQL Server

колонки DECIMAL(9,6) т. е. он поддерживает значения, такие как 999,123456.

но когда я вставляю данные, такие как 123,4567, он становится 123,456700

Как удалить эти нули?

22 ответов


A decimal(9,6) сохраняет 6 цифр в правой части запятой. Отображать конечные нули или нет-это решение о форматировании, обычно реализуемое на стороне клиента.

но так как форматы SSMS float без конечных нулей вы можете удалить конечные нули, бросив decimal до float:

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

принты:

123.456700  123,4567

(мой десятичный разделитель-это запятая, но SSMS форматирует decimal с точкой. Видимо,известно выпуск.)


можно использовать FORMAT() функция (SqlAzure и 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'

будьте осторожны при использовании с FLOAT (или REAL): не используйте g17 или больше (или g8 или больше с реальным), потому что ограниченная точность представления машины вызывает нежелательные эффекты:

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'

кроме того, обратите внимание, что в соответствии с документация:

формат зависит от наличия общего языка .NET Framework Среда выполнения (CLR). Эта функция не будет удалена, так как она зависит от наличие CLR. Удаленное выполнение функции, требующей CLR вызовет ошибку на удаленном сервере.

работает и в SqlAzure.


SELECT CONVERT(DOUBLE PRECISION, [ColumnName])

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

принты:

2.55

Cast(20.5500 as Decimal(6,2))

должен это сделать.


Я не хотел бросать, чтобы плавать из-за потенциала для большего количества цифр в моем десятичном, чем float может представлять

FORMAT при использовании со стандартной строкой формата .net " g8 " возвращается научная нотация в случаях очень малых десятичных знаков (например, 1e-08), которая также не подходит

использование строки пользовательского формата (https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings) позволил мне достичь того, чего я хотел:

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

Если вы хотите, чтобы ваш номер имел хотя бы один конечный ноль, поэтому 2.0 не становится 2, Используйте строку формата, такую как 0.0#####

десятичная точка локализована, поэтому культуры, которые используют запятую в качестве десятичного разделителя, столкнутся с запятыми, где . is

конечно, это обескураживающая практика форматирования слоя данных (но в моем случае нет другого слоя; пользователь буквально запускает хранимую процедуру и размещение результата в электронном письме :/)


У меня была аналогичная проблема, но также требовалось удалить десятичную точку, где десятичная не присутствовала, вот мое решение, которое разбивает десятичную дробь на ее компоненты и основывает количество символов, которые она берет из десятичной строки, на длине компонента дроби (без использования регистра). Чтобы сделать дело еще более интересным, мой номер был сохранен как поплавок без десятичных знаков.

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') 

результат болезненный, я знаю, но я получил там, с большой помощью из ответов выше.


лучший способ не конвертировать в FLOAT или деньги перед преобразованием из-за вероятности потери точности. Таким образом, безопасные способы могут быть примерно такими:

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

где @value может быть любой decimal (x,y)


мне нужно было удалить конечные нули на моих десятичных дробях, чтобы я мог вывести строку определенной длины только с ведущий нули

(например, мне нужно было вывести 14 символов, чтобы 142.023400 стал 000000142.0234),

Я parsename, reverse и cast as int чтобы удалить конечные нули:

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

(чтобы затем получить мои ведущие нули, я мог бы воспроизвести правильное количество нулей на основе длины выше и объединить это в передней части выше)

надеюсь, это кому-то поможет.


можно удалить ведущие и конечные нули в TSQL

  1. преобразовать его в строку с помощью функции STR TSQL если не строка, то

  2. удалить ведущие и конечные нули

    SELECT REPLACE(RTRIM(LTRIM(REPLACE(AccNo,'0',' '))),' ','0') AccNo FROM @BankAccount
    
  3. подробнее о форуме.


попробуйте это :

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

дает 20.55


другой вариант...

Я не знаю, насколько это эффективно, но, похоже, работает и не проходит через float:

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

средняя линия удаляет конечные пробелы, внешние два удаляют точку, если нет десятичных цифр


Как насчет этого? Предполагая, что данные поступают в вашу функцию как @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

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

Я понимаю, что это старый пост, но хотел бы предоставить SQL, который я придумал

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

Я знаю, что этот поток очень старый, но для тех, кто не использует SQL Server 2012 или выше или не может использовать функцию FORMAT по какой-либо причине, то следующие работы.

кроме того, многие решения не работали, если число было меньше 1 (например, 0.01230000).

обратите внимание, что не работает с отрицательными числами.

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') 

возвращает 10.012345 и 0.012345 соответственно.


попробуйте это.

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

самый простой способ-привести значение как FLOAT, а затем к строковому типу данных.

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

у меня была аналогичная проблема, необходимая для обрезки конечных нулей из чисел, таких как xx0000,x00000,xxx000

Я:

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

код-это имя поля с номером, который нужно обрезать. Надеюсь, это поможет кому-то еще.


десятичный (9,6) столбец преобразуется в float без потери точности, поэтому CAST(... AS float) сделает трюк.


@HLGEM: говорить, что float является плохим выбором для хранения чисел и" никогда не использовать float " не правильно - вы просто должны знать свои номера, например, измерения температуры будут идти хорошо, как поплавки.

@abatishchev и @japongskie: префиксы перед SQL, хранящиеся процессы и функции по-прежнему хорошая идея, если не требуется; ссылки, которые вы упомянутый только инструктирует не использовать префикс " sp_ "для хранимых процедур, которые вы не должны использовать, другие префиксы прекрасны, например" usp_ "или"spBob_"

ссылка: "Все целые числа с 6 или менее значимыми десятичными цифрами могут быть преобразованы в значение с плавающей запятой IEEE 754 без потери точности":https://en.wikipedia.org/wiki/Single-precision_floating-point_format


попробуйте это:

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

попробуйте это:

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