SQL Server'da ondalık sayıdan sondaki sıfırları kaldırın


85

Bir DECIMAL(9,6)sütunum var yani 999,123456 gibi değerleri destekliyor.

Ama 123.4567 gibi bir veri eklediğimde 123.456700 oluyor

Bu sıfırlar nasıl kaldırılır?


Lütfen doğru yanıtı @
Andomar'ın

@dangalg: Bunun gerçekten sunum katmanında yapılması gerektiğine inanıyorum. Bu yüzden kabul edilen cevabı asla değiştirmedim. Ancak daha fazla değerlendirmeden sonra, topluluğun hangi cevabın en iyi olduğunu açıkça belirttiğini kabul etmem gerektiğini düşünüyorum.
abatishchev

Yanıtlar:


147

A decimal(9,6), virgülün sağ tarafında 6 basamak saklar. Sondaki sıfırların gösterilip gösterilmeyeceği, genellikle istemci tarafında uygulanan bir biçimlendirme kararıdır.

Ama ssms formatları beri floatsondaki sıfırlar olmadan, sen döküm yoluyla sıfır sondaki kaldırabilirsiniz decimala float:

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

baskılar:

123.456700  123,4567

(Ondalık ayırıcım virgülden oluşuyor, ancak SSMS ondalık noktayı bir noktayla biçimlendiriyor. Görünüşe göre bilinen bir sorun .)


8
+1 Float'a dönüşümün sonuçlara bazı belirsizlik getireceğini düşündüm, ancak kesinlikle iyi çalışıyor gibi görünüyor.
Martin Smith

1
Bu yöntemin bir dezavantajı, "2.0" ile başlarsanız, onu "2" ye dönüştürmesidir. Bu, soruyu soran kişi için muhtemelen uygundur, ancak ondalık sayıdan sonra başka sıfırlar bırakmadan tek bir sıfır tutabilmem gerekiyordu. @ user1959416'nın cevabı bunu çözdü.
Mason G. Zhwiti

6
Artı şamandıra genel olarak sayıları saklamak için çok zayıf bir seçimdir. Tam bir tür olmadığı için yuvarlama hataları alacaksınız. Asla şamandıra kullanmayın.
HLGEM


Bir ondalık basamağın ölçeği ve kesinliğinin bir kayan noktayı geçebileceğini ve bu nedenle (17 basamaktan önemli biriyle) bu cevabın işe yaramadığı durumlar olabileceğini düşünürken doğru muyum?
Caius Jard

32

FORMAT()İşlevi kullanabilirsiniz (SqlAzure ve 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 (veya GERÇEK) ile kullanırken dikkatli olun: g17veya daha büyük (veya g8REAL ile daha büyük) kullanmayın, çünkü makine temsilinin sınırlı hassasiyeti istenmeyen etkilere neden olur:

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'

Ayrıca, belgelere göre şunları unutmayın :

FORMAT, .NET Framework Ortak Dil Çalışma Zamanı'nın (CLR) varlığına dayanır. CLR'nin varlığına bağlı olduğu için bu işlev uzaktan kumanda edilmeyecektir. CLR gerektiren bir işlevi yeniden başlatmak, uzak sunucuda bir hataya neden olur.

SqlAzure'de de çalışıyor.


Amaçlarım için, numaramı "1e-08" olarak biçimlendiren bir g8 biçim dizesi buldum, ki bu peşinde olduğum şey değildi. Bu cevap beni kullanabileceğim bir cevaba
Caius Jard

18
SELECT CONVERT(DOUBLE PRECISION, [ColumnName])

SQL Server 2008 ve üzeri
Bat_Programmer

numara "123.10705000000" gibi olduğunda ne olur? SELECT CONVERT (DOUBLE PRECISION, 123.10705000000) ile denedim ama cevap olarak bana "123.107" veriyor. ve çıktı olarak "123.10705" istiyorum? Herhangi bir yol var mı? CHARINDEX'i kullanmak istemiyorum.
Bhavika Zimbar

16

Float'ın temsil edebileceğinden daha fazla rakamın ondalık dilimde olma potansiyeli nedeniyle float'a dönüştürme konusunda isteksizdim

FORMAT standart .net formatlı bir dizeyle kullanıldığında 'g8', çok küçük ondalık sayılarda (örn. 1e-08) bilimsel gösterimi döndürdü ve bu da uygun değildi

Özel bir biçim dizesi kullanmak ( https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings ) istediğim şeyi elde etmemi sağladı:

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

Numaranızın sonunda en az bir sıfır olmasını istiyorsanız, böylece 2.0 2 olmaz, aşağıdaki gibi bir biçim dizesi kullanın 0.0#####

Ondalık nokta yerelleştirilmiştir, bu nedenle ondalık ayırıcı olarak virgül kullanan kültürler,. dır-dir

Elbette bu, veri katmanının biçimlendirme yapmasının tavsiye edilemeyecek bir uygulamasıdır (ancak benim durumumda başka bir katman yoktur; kullanıcı tam anlamıyla bir saklı yordamı çalıştırıyor ve sonucu bir e-postaya koyuyor: /)


Evet, bilimsel gösterimden kaçınırken, ondalık ayırıcının sağındaki sayılar üzerinde tam kontrol sağlayan tek çözüm budur. Bu çözümle ilgili tek sorun, FORMAT'ın gerçekten (!) Yavaş olmasıdır. (Hala .. SQL2019'da)
Tor

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

baskılar:

2.55

2
Bu yöntem, eğer sadece sıfır varsa, sonunda bir sıfır bırakacağı için güzeldir. Yani 2.5500, 2.55 döndürür ve 2.000, 2 yerine 2.0 döndürür. Bir araçta motor boyutlarını biçimlendirirken harika ...
Mason G. Zhwiti

4
@ MasonG.Zhwiti Bunun, 232.33220003200 gibi ondalık noktadan sonra daha fazla basamak içeren bir ondalık sayı ile çalışacağından şüpheliyim: -)
gotqn

@gotqn İyi nokta, bu kesinlikle başarısız. Bununla birlikte, özel kullanım durumumuz için (arabalardaki motor boyutlarını biçimlendirme) mükemmel çalışıyor. :)
Mason G. Zhwiti

@gotqn'un dediği gibi .. numara uzun olduğunda buggy
Ofear

Bu tam olarak 0,56000 gibi sayılar için geçerli değildir. 56 verecek. Komik
Gunjan Shakya


4

Bunu dene :

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

20,55 verir


1
DEĞİŞTİR (KIRP (DEĞİŞTİR (20,00, "0", "")), "", "0") sizi bir sonda bırakır. => "20."
Keith Sirmons

Benim durumuma mükemmel bir şekilde uygulanabilir ve en basit çözüm gibi görünüyor. Beğen ve oy ver!
Oak_3260548

Float'a dönüştürmek zorunda kalmadan harika çözüm! bir küçük bir sorun lekeli 0.000oldu .. işte SELECT REPLACE(RTRIM(REPLACE(20.5500, "0", " ")), " ", "0")sadece sondaki sıfırları kırpmak için düzeltme
wilson

2

Benzer bir sorunum vardı, ancak ondalık basamağın bulunmadığı ondalık noktayı da kaldırmam gerekiyordu, işte ondalık sayıları bileşenlerine bölen ve ondalık nokta dizesinden aldığı karakterlerin uzunluğunu temel alan çözümüm buydu. kesir bileşeni (CASE kullanmadan). Konuları daha da ilginç kılmak için, numaram ondalık sayıları olmadan bir kayan nokta olarak saklandı.

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

Sonuç acı verici, biliyorum, ama oraya yukarıdaki cevapların çok yardımıyla ulaştım.


2

En iyi yol, kesinlik kaybı ihtimali nedeniyle dönüştürmeden önce FLOAT veya PARA'ya dönüştürmemektir. Dolayısıyla güvenli yollar şunun gibi bir şey olabilir:

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 herhangi bir ondalık (x, y) olabilir


@abatishchev, fn_, sql işlevleri için tercih edilen bir önektir, önekler standart kodlama ve adlandırma kurallarında ve en iyi uygulamalarda kullanılır, öneklerimizi özelleştirebiliriz, ancak en iyi uygulamalar sp_için saklı yordam, fn_işlevler, tbltablolar vb. üzerinde ... bu bir gereklilik değildir, ancak bu, veritabanımızı düzenlemek için en iyi uygulamalardır.
japzdivino

@japongskie: üzgünüm ama hayır. Öneklere hiç gerek yoktur. Bu aslında en kötü uygulamadır. Bkz 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 ve çok daha fazlası
abatishchev

@abatishchev, anlıyorum .. bu yüzden artık okul öğretimini takip etmeyeceğim .. haha ​​LOL, bağlantınız mdsn'den geldiğinden, bunun için teşekkürler, şimdi en iyi uygulamamı değiştireceğim .. :)
japzdivino

2

Benzer bir sorun yaşadım, sondaki sıfırları aşağıdaki gibi sayılardan kırpmam gerekiyordu. xx0000,x00000,xxx000

Kullandım:

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

Kod, kırpılacak numaranın bulunduğu alanın adıdır. Umarım bu başka birine yardımcı olur.


Bu yorum, SQL Server'daki TRIM veya FORMAT yapı işlevlerini kullanamayacağınız kadar eski bir SQL Server sürümünü kullanıyorsanız iyi çalışır.
David Parvin

Bu cevapla ilgili bir sorun buldum. 'Kod' alanındaki değer '10' gibi bir şeyse, o zaman '1' döndürür. Sayı '10 .00 'ise, sanırım ondalık noktayı da yok sayıyor.
David Parvin

1

Başka seçenek...

Bunun ne kadar verimli olduğunu bilmiyorum ama işe yarıyor gibi görünüyor ve float ile gitmiyor:

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

Orta çizgi sondaki boşlukları çıkarır, dıştaki iki ondalık basamak yoksa noktayı kaldırır


1

Ondalık sayılarımın sonundaki sıfırları kaldırmam gerekiyordu, böylece yalnızca önde gelen belirli bir uzunlukta bir dize çıkarabilirdim sıfırlar

(örneğin 142.023400'ün 000000142.0234 olması için 14 karakter çıktı vermem gerekiyordu),

Kullandığım parsename, reverseve cast as intarka sıfır kaldırmak:

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

(Daha sonra baştaki sıfırlarımı elde etmek için, yukarıdakilerin uzunluğuna göre doğru sayıda sıfırları çoğaltabilir ve bunu yukarıdakinin önüne birleştirebilirim)

Umarım bu birine yardımcı olur.


@Protiguous 1 ondalık nokta olduğundan, 2.5500 <şema_adı>. <nesne_adı> gibi okunur. 2'nin ikinci parametresi şema adını, 1'in ikinci parametresi nesne adını döndürür. Genellikle, dbo veya PARSENAME ('dbo.TableName', 1) döndürmek için PARSENAME ('dbo.TableName', 2) gibi kullanılır ve TableName döndürülür.
Ali

Merhaba .. Yorumunuzda takma adımın işaretlendiğini görüyorum. Sebebini bilmiyorum?
Protiguous

26 Mayıs 2020'de bana sorduğun tam soru, "PARSENAME burada nasıl çalışacak ???" idi. Üzgünüm size cevap vermem çok uzun sürdü.
Ali

1

TSQL'de baştaki ve sondaki sıfırları kaldırmak mümkündür

  1. Dize değilse STR TSQL işlevini kullanarak dizgeye dönüştürün, Sonra

  2. Baştaki ve sondaki sıfırları kaldırın

    SELECT REPLACE(RTRIM(LTRIM(REPLACE(AccNo,'0',' '))),' ','0') AccNo FROM @BankAccount
    
  3. Forum hakkında daha fazla bilgi .


4
Biraz çirkin ama bu sürüm arta kalanları öldürüyor '.':REPLACE(RTRIM(REPLACE(REPLACE(RTRIM(REPLACE(X,'0',' ')),' ','0'),'.',' ')),' ','.')
Chris B

1
Dikkatli olun, sayı ondalık değilse sıfırları da kırpacaktır. CHARINDEX ('.', @ Number)! = 1 bunu test edecek.
Muflix

Önceki ondalık kontrolüm yanlış. İşte daha iyisi: Len (@Test) - Len (Replace (@Test, 'a', '')) NumberOfCharacters Explained olarak seçin: tinyurl.com/o4fc8g7 ve tinyurl.com/kgzkuqk
Muflix

0

Buna ne dersin? İşlevinize @thisData olarak gelen verileri varsayarsak:

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

Bu aynı zamanda sayılar arasındaki 0'ların (sıfırların) yerini almaz mıydı? Dont 'think replace sadece sonunda işe
yarar

0

Bunun eski bir gönderi olduğunu anlıyorum ancak bulduğum SQL'i sağlamak istiyorum

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

bunu dene.

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

0

En kolay yol, değeri FLOAT olarak ve ardından bir dize veri türü olarak CAST yapmaktır.

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

-1

Bunu dene:

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

Değerleri değiştirmediği için @ user1959416'nın cevabını burada daha iyi tercih ediyorum. Örneğin, 2,5550 ile başlayarak, yönteminiz 2,56 ile sonuçlanırken, onlarınki 2,555 döndürür.
Mason G. Zhwiti

-1

Bu iş parçacığının çok eski olduğunu biliyorum ancak SQL Server 2012 veya üzeri kullanmayanlar veya herhangi bir nedenle FORMAT işlevini kullanamayanlar için aşağıdakiler çalışıyor.

Ayrıca, sayı 1'den küçükse çözümlerin çoğu işe yaramadı (ör. 0,01230000).

Lütfen aşağıdakilerin negatif sayılarla çalışmadığını unutmayın.

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

Sırasıyla 10.012345 ve 0.012345 döndürür.


-1

Bunu dene:

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

bu geri döner 999999, OP sondaki sıfırları kaldırmayı ister.
japzdivino

-1

Ondalık (9,6) sütunu, hassasiyet kaybı olmaksızın kayan noktaya dönüşür, bu nedenle CAST (... AS float) hile yapar.


@HLGEM: Float'ın sayıları saklamak için kötü bir seçim olduğunu ve "Asla float kullanmayın" demek doğru değildir - sadece sayılarınızı bilmeniz gerekir, örneğin sıcaklık ölçümleri float gibi iyi gider.

@abatishchev ve @japongskie: SQL'de depolanan işlemlerin ve işlevlerin önündeki ön ekler, gerekmiyorsa yine de iyi bir fikirdir; Bahsettiğiniz bağlantılar, kullanmamanız gereken saklı yordamlar için yalnızca "sp_" önekini kullanmama talimatı verir, diğer önekler uygundur, örneğin "usp_" veya "spBob_"

Referans: "6 veya daha az ondalık basamağa sahip tüm tamsayılar, hassasiyet kaybı olmadan IEEE 754 kayan noktalı değere dönüştürülebilir": https://en.wikipedia.org/wiki/Single-precision_floating-point_format

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.