Удалить завершающие нули из десятичного числа в SQL Server - PullRequest
72 голосов
/ 30 мая 2010

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

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

Как убрать эти нули?

Ответы [ 22 ]

124 голосов
/ 30 мая 2010

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 форматирует десятичную с точкой. По-видимому, известная проблема .)

28 голосов
/ 30 августа 2013

Вы можете использовать функцию 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 или больше с REAL), поскольку ограниченная точность представления машины вызывает нежелательные эффекты:

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'

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

FORMAT опирается на наличие общего языка .NET Framework. Время выполнения (CLR). Эта функция не будет удалена, поскольку она зависит от наличие клр. Remoting функция, которая требует CLR может вызвать ошибку на удаленном сервере.

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

13 голосов
/ 23 июня 2015
SELECT CONVERT(DOUBLE PRECISION, [ColumnName])
9 голосов
/ 16 мая 2018

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

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#####

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

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

6 голосов
/ 09 января 2013
SELECT REVERSE(ROUND(REVERSE(2.5500),1))

печать:

2.55
3 голосов
/ 24 апреля 2014
Cast(20.5500 as Decimal(6,2))

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

2 голосов
/ 11 декабря 2014

Лучший способ - НЕ конвертировать в 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 может быть любой десятичный (x, y)

2 голосов
/ 03 июня 2014

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

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

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

2 голосов
/ 10 августа 2016

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

Я использовал:

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

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

1 голос
/ 25 апреля 2013

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

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

Я использовал parsename, reverse и cast as int, чтобы удалить завершающие нули:

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

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

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

...