Xóa các số không ở cuối khỏi hệ thập phân trong SQL Server


85

Tôi có một cột DECIMAL(9,6)tức là nó hỗ trợ các giá trị như 999,123456.

Nhưng khi tôi chèn dữ liệu như 123,4567, nó sẽ trở thành 123,456700

Làm thế nào để loại bỏ những số không?


Vui lòng thay đổi câu trả lời đúng thành câu trả lời của @ Andomar
dangalg Ngày

@dangalg: Tôi thực sự tin rằng điều này nên được thực hiện trong lớp trình bày. Đó là lý do tại sao tôi không bao giờ thay đổi câu trả lời đã được chấp nhận. Tuy nhiên, sau khi cân nhắc thêm, tôi nghĩ tôi nên chấp nhận những gì cộng đồng đã chỉ ra rõ ràng câu trả lời nào là tốt nhất.
abatishchev

Câu trả lời:


147

A decimal(9,6)lưu 6 chữ số bên phải dấu phẩy. Việc có hiển thị các số 0 ở cuối hay không là một quyết định định dạng, thường được thực hiện ở phía máy khách.

Nhưng vì các định dạng SSMS floatkhông có số 0 ở cuối, bạn có thể xóa các số 0 ở cuối bằng cách decimalchuyển thành float:

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

bản in:

123.456700  123,4567

(Dấu phân tách thập phân của tôi là dấu phẩy, nhưng SSMS định dạng thập phân với dấu chấm. Rõ ràng là một vấn đề đã biết .)


8
+1 Tôi nghĩ rằng việc chuyển đổi thành float sẽ dẫn đến một số kết quả không chính xác nhưng nó có vẻ hoạt động hoàn toàn tốt.
Martin Smith

1
Một nhược điểm của phương pháp này là nếu bạn bắt đầu bằng "2.0", nó sẽ biến nó thành "2". Điều này có thể ổn đối với người đặt câu hỏi, nhưng tôi cần phải có thể giữ một số 0 duy nhất sau số thập phân, mà không giữ bất kỳ số 0 ở cuối nào khác. Câu trả lời của @ user1959416 giải quyết được điều đó.
Mason G. Zhwiti

6
Plus float nói chung là một lựa chọn rất tồi để lưu trữ số. Bạn sẽ gặp lỗi làm tròn vì nó không phải là kiểu chính xác. Không bao giờ sử dụng phao.
HLGEM

Các bình luận về nổi được định dạng mà không cần số không dấu được cực kỳ hữu ích
Sanjiv Jivan

Tôi có đúng khi nghĩ rằng tỷ lệ và độ chính xác của một số thập phân có thể vượt quá tỷ lệ của một số float và do đó có thể có trường hợp (với số có nghĩa nhiều hơn 17 chữ số) câu trả lời này không thành công?
Caius Jard

32

Bạn có thể sử dụng FORMAT()chức năng (SqlAzure và 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'

Cẩn thận khi sử dụng với FLOAT (hoặc REAL): không sử dụng g17hoặc lớn hơn ( g8hoặc lớn hơn với REAL), vì độ chính xác hạn chế của biểu diễn máy gây ra các tác dụng không mong muốn:

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'

Hơn nữa, hãy lưu ý rằng, theo tài liệu :

FORMAT dựa trên sự hiện diện của .NET Framework Common Language Runtime (CLR). Chức năng này sẽ không được khởi động lại vì nó phụ thuộc vào sự hiện diện của CLR. Việc khởi động lại một chức năng yêu cầu CLR sẽ gây ra lỗi trên máy chủ từ xa.

Cũng hoạt động trong SqlAzure.


Vì mục đích của mình, tôi đã tìm thấy một chuỗi định dạng g8 được định dạng số của tôi là "1e-08", đây không phải là chuỗi mà tôi đang theo đuổi. Câu trả lời này đã dẫn tôi đến một câu trả lời mà tôi có thể sử dụng
Caius Jard

17
SELECT CONVERT(DOUBLE PRECISION, [ColumnName])

SQL Server 2008 trở lên
Bat_Programmer

điều gì sẽ xảy ra khi số giống như "123.10705000000"? Tôi đã thử với CHỌN CHUYỂN ĐỔI (DOUBLE CHÍNH XÁC, 123.10705000000) nhưng nó cho tôi câu trả lời là "123.107". và tôi muốn "123.10705" làm đầu ra? Không có cách nào khác ư? Tôi không muốn sử dụng CHARINDEX.
Bhavika Zimbar

16

Tôi đã miễn cưỡng chuyển sang float vì khả năng có nhiều chữ số trong số thập phân của tôi hơn số float có thể đại diện

FORMAT khi được sử dụng với chuỗi định dạng .net tiêu chuẩn 'g8' trả về ký hiệu khoa học trong các trường hợp số thập phân rất nhỏ (ví dụ: 1e-08) cũng không phù hợp

Sử dụng chuỗi định dạng tùy chỉnh ( https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings ) cho phép tôi đạt được những gì tôi muốn:

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

Nếu bạn muốn số của mình có ít nhất một số 0 ở cuối, vì vậy 2.0 không trở thành 2, hãy sử dụng chuỗi định dạng như 0.0#####

Dấu thập phân được bản địa hóa, vì vậy các nền văn hóa sử dụng dấu phẩy làm dấu phân tách thập phân sẽ gặp phải đầu ra dấu phẩy trong đó. Là

Tất nhiên, đây là thực tế không khuyến khích khi để lớp dữ liệu thực hiện định dạng (nhưng trong trường hợp của tôi thì không có lớp nào khác; người dùng thực sự đang chạy một thủ tục được lưu trữ và đưa kết quả vào email: /)


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

bản in:

2.55

2
Phương pháp này hay ở chỗ nó sẽ để lại một số 0 ở cuối nếu chỉ có một số 0. Vì vậy, lợi nhuận 2,5500 2,55, và 2.000 lợi nhuận 2.0 chứ không phải 2. Tuyệt vời cho khi bạn định dạng kích thước động cơ trong một chiếc xe ...
Mason G. Zhwiti

4
@ MasonG.Zhwiti Tôi nghi ngờ điều này sẽ hoạt động với một số thập phân có nhiều chữ số hơn sau dấu thập phân như 232.33220003200 chẳng hạn: -)
gotqn

@gotqn Điểm tốt, điều đó chắc chắn không thành công. Tuy nhiên, đối với trường hợp sử dụng cụ thể của chúng tôi (định dạng kích thước động cơ trên ô tô), nó hoạt động hoàn hảo. :)
Mason G. Zhwiti

như @gotqn nói .. đó là lỗi khi số dài
Ofear

Điều này không chính xác hoạt động đối với các số như 0,56000. nó sẽ mang lại 56. vui
Gunjan Shakya


3

Thử đi :

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

Cho 20,55


1
REPLACE (TRIM (REPLACE (20,00, "0", "")), "", "0") để lại dấu vết cho bạn. => "20."
Keith Sirmons

Nó hoàn toàn có thể áp dụng cho trường hợp của tôi và dường như là giải pháp đơn giản nhất. Ngón tay cái và bình chọn!
Oak_3260548,

Giải pháp tuyệt vời mà không cần phải chuyển đổi sang float! một vấn đề nhỏ được phát hiện 0.000đã trở thành .. đây là bản sửa lỗi SELECT REPLACE(RTRIM(REPLACE(20.5500, "0", " ")), " ", "0")để chỉ cắt các số không ở cuối
wilson

2

Tôi đã gặp sự cố tương tự nhưng cũng được yêu cầu xóa dấu thập phân nơi không có số thập phân, đây là giải pháp của tôi chia số thập phân thành các thành phần của nó và căn cứ vào số ký tự mà nó lấy từ chuỗi dấu thập phân trên độ dài của thành phần phân số (không sử dụng CASE). Để làm cho vấn đề thú vị hơn nữa, số của tôi đã được lưu trữ dưới dạng một phao không có số thập phân.

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

Kết quả là đau đớn, tôi biết, nhưng tôi đã đạt được điều đó, với sự trợ giúp rất nhiều từ những câu trả lời ở trên.


2

Cách tốt nhất là KHÔNG chuyển đổi sang FLOAT hoặc MONEY trước khi chuyển đổi vì có thể mất độ chính xác. Vì vậy, các cách an toàn có thể giống như sau:

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

trong đó @value có thể là bất kỳ số thập phân nào (x, y)


@abatishchev, fn_ là một tiền tố được ưu tiên cho các chức năng sql, các tiền tố được sử dụng trong tiêu chuẩn mã hóa và quy ước đặt tên cũng như thực hành tốt nhất, chúng tôi có thể tùy chỉnh các tiền tố của chúng tôi, nhưng đối với thực hành tốt nhất chúng tôi sử dụng sp_cho thủ tục lưu trữ, fn_cho các chức năng, tblcho các bảng và do đó về ... đây không phải là một yêu cầu nhưng đây là phương pháp hay nhất để tổ chức cơ sở dữ liệu của chúng tôi.
japzdivino

@japongskie: xin lỗi, nhưng không. Không cần tiền tố. Đây thực sự là cách thực hành tồi tệ nhất. Xem 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 và nhiều hơn nữa
abatishchev

@abatishchev, oh tôi hiểu rồi .. vì vậy tôi sẽ không theo việc giảng dạy ở trường nữa .. haha ​​LOL, vì liên kết của bạn đến từ mdsn, cảm ơn vì liên kết này, tôi sẽ thay đổi ngay bây giờ phương pháp tốt nhất của tôi .. :)
japzdivino

2

Tôi đã gặp sự cố tương tự, cần phải cắt các số không ở cuối khỏi các số như xx0000,x00000,xxx000

Tôi đã sử dụng:

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

Mã là tên của trường có số được cắt bớt. Hy vọng điều này sẽ giúp người khác.


Nhận xét này hoạt động tốt khi bạn đang sử dụng phiên bản SQL Server đủ cũ để bạn không thể sử dụng hàm TRIM hoặc FORMAT tích hợp trong SQL Server.
David Parvin

Tôi đã tìm thấy một vấn đề với câu trả lời này. Nếu giá trị trong trường 'mã' giống như '10' thì nó sẽ trả về '1'. Nếu số là '10 .00', tôi nghĩ nó cũng bỏ qua dấu thập phân.
David Parvin

1

Một lựa chọn khác ...

Tôi không biết điều này hiệu quả như thế nào nhưng nó có vẻ hoạt động và không đi qua float:

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

Dòng giữa loại bỏ dấu cách ở cuối, hai dòng ngoài xóa dấu chấm nếu không có chữ số thập phân


1

Tôi cần xóa các số không ở cuối trên số thập phân của mình để tôi có thể xuất một chuỗi có độ dài nhất định chỉ với các số 0 ở đầu

(ví dụ: tôi cần xuất ra 14 ký tự để 142.023400 sẽ trở thành 000000142.0234),

Tôi đã sử dụng parsename, reversecast as intđể loại bỏ các số không dấu:

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

(Để có được các số 0 ở đầu của tôi, tôi có thể sao chép đúng số lượng các số không dựa trên độ dài của số trên và nối số này với phía trước của số trên)

Tôi hi vọng nó sẽ giúp ích cho mọi người.


@Protiguous Vì có 1 dấu thập phân nên 2.5500 được đọc giống như <schema_name>. <object_name>. Tham số thứ hai của 2 trả về tên lược đồ, tham số thứ hai của 1 trả về tên đối tượng. Nó thường được sử dụng như PARSENAME ('dbo.TableName', 2) để trả về dbo hoặc PARSENAME ('dbo.TableName', 1) để trả về TableName.
Ali

Xin chào .. Tôi thấy bí danh của tôi được gắn cờ trong nhận xét của bạn. Tôi không biết tại sao?
Protiguous

Câu hỏi chính xác mà bạn đã hỏi tôi vào ngày 26 tháng 5 năm 2020 là "PARSENAME hoạt động ở đây như thế nào ???" Xin lỗi vì đã mất quá nhiều thời gian để trả lời bạn.
Ali

1

có thể loại bỏ các số không ở đầu và cuối trong TSQL

  1. Chuyển nó thành chuỗi bằng cách sử dụng hàm STR TSQL nếu không phải là chuỗi, Sau đó

  2. Xóa cả số không ở đầu và ở cuối

    SELECT REPLACE(RTRIM(LTRIM(REPLACE(AccNo,'0',' '))),' ','0') AccNo FROM @BankAccount
    
  3. Thêm thông tin trên diễn đàn .


4
Một chút xấu xí nhưng phiên bản này giết chết những thứ còn sót lại '.':REPLACE(RTRIM(REPLACE(REPLACE(RTRIM(REPLACE(X,'0',' ')),' ','0'),'.',' ')),' ','.')
Chris B

1
Hãy cẩn thận, nếu số không phải là số thập phân, nó cũng sẽ cắt bớt số 0. CHARINDEX ('.', @ Number)! = 1 sẽ kiểm tra điều đó.
Muflix

Lần kiểm tra số thập phân trước đây của tôi là sai. Ở đây tốt hơn: Chọn Len (@Test) - Len (Thay thế (@Test, 'a', '')) Làm NumberOfCharacters Giải thích: tinyurl.com/o4fc8g7tinyurl.com/kgzkuqk
Muflix 28/02/15

0

Còn cái này thì sao? Giả sử dữ liệu đi vào chức năng của bạn dưới dạng @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

Wounld không phải điều này cũng thay thế các số 0 (số không) ở giữa các số? Đừng 'nghĩ rằng thay thế chỉ hoạt động ở cuối ...
mtk

0

Tôi hiểu đây là một bài đăng cũ nhưng tôi muốn cung cấp SQL mà tôi đã nghĩ ra

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

thử đi.

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

0

Cách dễ nhất là CAST giá trị dưới dạng FLOAT và sau đó là kiểu dữ liệu chuỗi.

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

-1

Thử đi:

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

Tôi thích câu trả lời của @ user1959416 hơn ở đây, vì nó không thay đổi các giá trị. Ví dụ: bắt đầu bằng 2,5550, phương thức của bạn cho kết quả là 2,56, trong khi phương thức của chúng trả về 2,555.
Mason G. Zhwiti

-1

Tôi biết chủ đề này rất cũ nhưng đối với những người không sử dụng SQL Server 2012 trở lên hoặc không thể sử dụng chức năng FORMAT vì bất kỳ lý do nào thì những điều sau sẽ hoạt động.

Ngoài ra, rất nhiều giải pháp không hoạt động nếu số nhỏ hơn 1 (ví dụ: 0,01230000).

Xin lưu ý rằng điều sau đây không hoạt động với số âm.

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

Trả về lần lượt là 10,012345 và 0,012345.


-1

Thử đi:

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

cái này trả về 999999, OP yêu cầu loại bỏ các số không ở cuối.
japzdivino

-1

Cột DECIMAL (9,6) sẽ chuyển thành float mà không làm mất độ chính xác, vì vậy CAST (... AS float) sẽ thực hiện thủ thuật.


@HLGEM: nói rằng float là một lựa chọn tồi để lưu trữ các số và "Không bao giờ sử dụng float" là không đúng - bạn chỉ cần biết các số của mình, ví dụ như các phép đo nhiệt độ sẽ tốt như phao.

@abatishchev và @japongskie: tiền tố phía trước các hàm và procs được lưu trữ SQL vẫn là một ý tưởng hay, nếu không bắt buộc; các liên kết bạn đã đề cập chỉ hướng dẫn không sử dụng tiền tố "sp_" cho các thủ tục được lưu trữ mà bạn không nên sử dụng, các tiền tố khác cũng được, ví dụ "usp_" hoặc "spBob_"

Tham khảo: "Tất cả các số nguyên có 6 chữ số thập phân có nghĩa trở xuống có thể được chuyển đổi thành giá trị dấu phẩy động IEEE 754 mà không làm mất độ chính xác": https://en.wikipedia.org/wiki/Single-pre khít_floating-point_format

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.