在SQL Server中从十进制删除尾随零


85

我有一列,DECIMAL(9,6)即它支持999,123456之类的值。

但是当我插入数据123,4567时,它变成123,456700

如何删除这些零?


请更改正确答案为@Andomar的答案
dangalg 18-3-20

@dangalg:我坚信这确实应该在表示层中完成。这就是为什么我从未更改过接受的答案的原因。但是,经过进一步的考虑,我认为我应该接受社区明确指出的答案的最佳答案。
abatishchev

Answers:


147

Adecimal(9,6)在逗号的右边存储6位数字。是否显示尾随零是格式决定,通常在客户端实施。

但是,由于SSMS格式float不带尾随零,因此可以通过将强制零转换decimal为a 来消除尾随零float

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

印刷品:

123.456700  123,4567

(我的小数点分隔符是逗号,但SSMS格式化带点的小数点。显然是已知问题。)


8
+1我认为将其转换为float会给结果带来一些不精确之处,但看起来效果很好。
马丁·史密斯

1
这种方法的一个缺点是,如果您以“ 2.0”开头,它将变成“ 2”。这对于问这个问题的人来说可能是可以的,但是我需要能够在小数点后保留一个零,而又不保留其他任何尾随零。@ user1959416的答案解决了这个问题。
Mason G. Zhwiti 2013年

6
一般而言,加上浮点数是存储数字的非常差的选择。您将舍入错误,因为它不是确切的类型。切勿使用浮子。
HLGEM 2013年

关于将浮点数格式化为不带零结尾的注释非常有用
Sanjiv Jivan 2016年

我是否正确地认为,小数的小数位数和精度可以超过浮点数,因此在某些情况下(有效位数超过17位),此答案可能无法解决吗?
凯斯·贾德

31

您可以使用该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)的存在。由于取决于CLR的存在,因此不会远程控制此功能。远程处理需要CLR的功能会在远程服务器上导致错误。

也可以在SqlAzure中使用。


出于我的目的,我找到了g8格式的字符串,将我的数字格式化为“ 1e-08”,这不是我想要的。这个答案的确使我找到了一个可以使用的答案
Caius Jard,

17
SELECT CONVERT(DOUBLE PRECISION, [ColumnName])

SQL Server 2008及更高版本
Bat_Programmer15年

当数字是“ 123.10705000000”时会发生什么?我尝试使用SELECT CONVERT(DOUBLE PRECISION,123.10705000000),但它给了我“ 123.107”作为答案。我想要“ 123.10705”作为输出?有什么办法吗?我不想使用CHARINDEX。
Bhavika Zimbar '16

15

我不愿强制使用浮点数,因为在小数点中可能有比浮点数所能代表的位数更多的数字

FORMAT 当与标准.net格式字符串'g8'一起使用时,如果小数位数很小(例如1e-08),则返回科学计数法,这也不适合

使用自定义格式字符串(https://docs.microsoft.com/zh-cn/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
SELECT REVERSE(ROUND(REVERSE(2.5500),1))

印刷品:

2.55

2
这种方法的好处在于,如果只有零,它将留下尾随的零。因此2.5500返回2.55,而2.000返回2.0,而不是2。非常适合在车辆中格式化发动机尺寸时使用
Mason G. Zhwiti 2013年

4
@ MasonG.Zhwiti我怀疑这是否可以使用一些小数点后的小数点后有更多数字,例如232.33220003200:-)
gotqn 2013年

@gotqn好一点,那肯定失败了。但是,对于我们的特定用例(格式化汽车中的发动机尺寸),它可以完美地工作。:)
Mason G. Zhwiti

如@gotqn所说..当号码很长时,这是越野车
Ofear

这不适用于0.56000之类的数字。它将产生56。搞笑
Gunjan Shakya


3

试试这个 :

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

给出20.55


1
REPLACE(TRIM(REPLACE(20.00,“ 0”,“”)),“”,“ 0”)留下尾随。=>“ 20”。
基思·西蒙斯

它完全适用于我的情况,似乎是最简单的解决方案。大拇指并投票!
Oak_3260548 '19

无需转换为浮动的绝佳解决方案!一个小问题看准0.000成了.。这是SELECT REPLACE(RTRIM(REPLACE(20.5500, "0", " ")), " ", "0")仅修整尾随零点的方法
威尔森

2

我有一个类似的问题,但是还需要删除不存在小数的小数点,这是我的解决方案,它将小数拆分为各个部分,并根据小数点字符串的长度将其从小数点字符串中提取的字符数作为基础分数成分(不使用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

最好的方法是在转换之前不要转换为FLOATMONEY,因为这会失去精度。因此,安全方式可以是这样的:

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)


@abatishchev,fn_是sql函数的首选前缀,前缀用于标准编码和命名约定以及最佳实践,我们可以自定义前缀,但是对于最佳实践,我们sp_用于存储过程,fn_函数,tbl表等。在...上,这不是必需的,但这是组织我们的数据库的最佳实践。
japzdivino

@japongskie:对不起,但是没有。完全不需要前缀。这实际上是最糟糕的做法。请参阅msdn.microsoft.com/zh-CN/library/dd172115(v=vs.100).aspx sqlperformance.com/2012/10/t-sql-queries/sp_prefix dba.stackexchange.com/q/25348/3186和还有更多
abatishchev,2016年

@abatishchev,哦,我明白了。所以我将不再按照学校的教学进行..哈哈,哈哈,由于您的链接来自mdsn,谢谢,我现在将改变我的最佳做法.. :)
japzdivino

2

我有一个类似的问题,需要从数字中删除尾随零 xx0000,x00000,xxx000

我用了:

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

代码是带有要修剪的数字的字段名称。希望这对其他人有帮助。


当您使用的SQL Server版本足够旧而无法在SQL Server中使用TRIM或FORMAT内置函数时,此注释很好用。
David Parvin

我确实找到了这个问题的一个问题。如果“代码”字段中的值类似于“ 10”,则它将返回“ 1”。如果数字是“ 10.00”,我认为它也忽略了小数点。
David Parvin

1

另外一个选项...

我不知道这有多有效,但它似乎有效并且不能通过float进行操作:

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

如果没有小数位数,则中间的一行将删除尾部空格,而外部的两个则删除该点


1

我需要删除小数点后的零,以便我可以输出一定长度的字符串,并且仅以前导

(例如,我需要输出14个字符,以便142.023400变为000000142.0234),

我使用parsenamereversecast as int删除了结尾的零:

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

(然后,为了得到我的前导零,我可以根据上面的长度复制正确数量的零,并将其连接到上面的前面)

我希望这对某人有帮助。


@Protiguous由于小数点为1,因此像<schema_name>。<object_name>一样读取2.5500。第二个参数2返回架构名称,第二个参数1返回对象名称。通常将其与PARSENAME('dbo.TableName',2)一起使用来返回dbo或PARSENAME('dbo.TableName',1)来返回TableName来使用。
阿里

您好..我看到您的评论中标记了我的别名。我不知道为什么?
毗邻

您在2020年5月26日问我的确切问题是“ PARSENAME应该如何在这里工作?” 抱歉,花了很长时间回复您。
阿里

1

可以删除TSQL中的前导和尾随零

  1. 如果不是字符串,则使用STR TSQL函数将其转换为字符串,然后

  2. 删除前导零和尾随零

    SELECT REPLACE(RTRIM(LTRIM(REPLACE(AccNo,'0',' '))),' ','0') AccNo FROM @BankAccount
    
  3. 有关论坛的更多信息。


4
有点丑陋,但此版本杀死了剩余的'。':REPLACE(RTRIM(REPLACE(REPLACE(RTRIM(REPLACE(X,'0',' ')),' ','0'),'.',' ')),' ','.')
Chris B

1
请注意,如果数字不是小数,它也会修剪零。CHARINDEX('。',@ Number)!= 1将对其进行测试。
Muflix

我以前的十进制检查是错误的。更好的方法是:按NumberOfCharacters的说明选择Len(@Test)-Len(Replace(@Test,'a','')):tinyurl.com/o4fc8g7tinyurl.com/kgzkuqk
Muflix

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

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

难道这还不能替换数字之间的0(零)吗?不要以为替换只会在末端起作用...
mtk 2014年

0

我知道这是一篇旧文章,但想提供我提出的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


0

最简单的方法是将值CAST转换为FLOAT,然后转换为字符串数据类型。

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

-1

试试这个:

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

我更喜欢@ user1959416的答案,因为它不会更改值。例如,从2.5550开始,您的方法将得出2.56,而其方法将返回2.555。
Mason G. Zhwiti 2013年

-1

我知道此线程非常旧,但是对于那些不使用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。


-1

试试这个:

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

此返回999999,OP要求删除尾随零。
japzdivino

-1

DECIMAL(9,6)列将转换为float而不损失精度,因此CAST(... AS float)将解决问题。


@HLGEM:说浮点数是存储数字的不佳选择,“永远不要使用浮点数”是不正确的-您只需要知道数字,例如温度测量就可以很好地适应浮点数。

@abatishchev和@japongskie:如果不需要的话,在SQL存储的proc和函数前面的前缀仍然是一个好主意;您提到的链接仅指示不要对不应使用的存储过程使用“ sp_”前缀,其他前缀也可以,例如“ usp_”或“ spBob_”

参考:“所有有效位数不超过6个或更少的整数都可以转换为IEEE 754浮点值而不会损失精度”:https : //en.wikipedia.org/wiki/Single-precision_floating-point_format

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.