Entfernen Sie nachfolgende Nullen von der Dezimalstelle in SQL Server


84

Ich habe eine Kolumne DECIMAL(9,6) dh sie unterstützt Werte wie 999.123456.

Aber wenn ich Daten wie 123,4567 einfüge, wird es 123,456700

Wie entferne ich diese Nullen?


Bitte ändern Sie die richtige Antwort auf @ Andomars Antwort
dangalg

@dangalg: Ich bin der festen Überzeugung, dass dies tatsächlich in der Präsentationsebene erfolgen sollte. Deshalb habe ich die akzeptierte Antwort nie geändert. Nach weiteren Überlegungen denke ich jedoch, ich sollte akzeptieren, was die Community klar angegeben hat, welche Antwort die beste ist.
Abatishchev

Antworten:


146

A decimal(9,6)speichert 6 Ziffern auf der rechten Seite des Kommas. Ob nachgestellte Nullen angezeigt werden sollen oder nicht, ist eine Formatierungsentscheidung, die normalerweise auf der Clientseite implementiert wird.

Aber da SSMS Formate floatohne nachfolgende Nullen können Sie Nullen Hinter entfernen , indem Sie das Gießen decimalauf ein float:

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

Drucke:

123.456700  123,4567

(Mein Dezimaltrennzeichen ist ein Komma, aber SSMS formatiert die Dezimalstelle mit einem Punkt. Anscheinend ein bekanntes Problem .)


8
+1 Ich dachte, die Umstellung auf Float würde zu einer gewissen Ungenauigkeit der Ergebnisse führen, aber es scheint absolut in Ordnung zu sein.
Martin Smith

1
Ein Nachteil dieser Methode ist, wenn Sie mit "2.0" beginnen, wird daraus "2". Dies ist wahrscheinlich in Ordnung für die Person, die die Frage stellt, aber ich musste in der Lage sein, eine einzelne Null nach der Dezimalstelle beizubehalten, ohne andere nachfolgende Nullen beizubehalten. Die Antwort von @ user1959416 löst das.
Mason G. Zhwiti

6
Außerdem ist Float im Allgemeinen eine sehr schlechte Wahl für die Speicherung von Zahlen. Sie erhalten Rundungsfehler, da es sich nicht um einen exakten Typ handelt. Verwenden Sie niemals einen Schwimmer.
HLGEM

Der Kommentar über das Formatieren von Floats ohne nachgestellte Nullen war äußerst nützlich
Sanjiv Jivan

Habe ich Recht, wenn ich denke, dass die Skalierung und Genauigkeit einer Dezimalstelle die eines Gleitkommas überschreiten kann und es daher Fälle geben kann, in denen diese Antwort (mit einer Signifikanz von mehr als 17 Stellen) nicht funktioniert?
Caius Jard

31

Sie können die FORMAT()Funktion verwenden (SqlAzure und 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'

Seien Sie vorsichtig bei der Verwendung mit FLOAT (oder REAL): Verwenden Sie nicht g17oder größer (oder g8größer mit REAL), da die begrenzte Genauigkeit der Maschinendarstellung unerwünschte Effekte verursacht:

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'

Beachten Sie außerdem, dass gemäß der Dokumentation :

FORMAT basiert auf dem Vorhandensein der .NET Framework Common Language Runtime (CLR). Diese Funktion wird nicht entfernt, da sie vom Vorhandensein der CLR abhängt. Das Remoten einer Funktion, für die die CLR erforderlich ist, würde einen Fehler auf dem Remoteserver verursachen.

Funktioniert auch in SqlAzure.


Für meine Zwecke fand ich eine Formatzeichenfolge von g8, die meine Nummer als "1e-08" formatierte, was nicht das war, wonach ich suchte. Diese Antwort führte mich zu einer, die ich verwenden konnte
Caius Jard

17
SELECT CONVERT(DOUBLE PRECISION, [ColumnName])

SQL Server 2008 und höher
Bat_Programmer

Was passiert, wenn die Nummer "123.10705000000" lautet? Ich habe es mit SELECT CONVERT (DOUBLE PRECISION, 123.10705000000) versucht, aber es gibt mir "123.107" als Antwort. und ich möchte "123.10705" als Ausgabe? Gibt es irgendeinen Weg? Ich möchte CHARINDEX nicht verwenden.
Bhavika Zimbar

14

Ich wollte nicht in Float umwandeln, da möglicherweise mehr Ziffern in meiner Dezimalstelle stehen, als Float darstellen kann

FORMAT Bei Verwendung mit einem Standard-.net-Format gab die Zeichenfolge 'g8' die wissenschaftliche Notation bei sehr kleinen Dezimalstellen (z. B. 1e-08) zurück, was ebenfalls ungeeignet war

Durch die Verwendung einer benutzerdefinierten Formatzeichenfolge ( https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings ) konnte ich das erreichen, was ich wollte:

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

Wenn Sie möchten, dass Ihre Zahl mindestens eine nachgestellte Null hat, damit aus 2.0 nicht 2 wird, verwenden Sie eine Formatzeichenfolge wie 0.0#####

Der Dezimalpunkt ist lokalisiert, sodass Kulturen, die ein Komma als Dezimaltrennzeichen verwenden, auf eine Kommaausgabe stoßen, bei der die. ist

Dies ist natürlich die unangenehme Praxis, die Datenschicht formatieren zu lassen (aber in meinem Fall gibt es keine andere Schicht; der Benutzer führt buchstäblich eine gespeicherte Prozedur aus und schreibt das Ergebnis in eine E-Mail: /)


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

Drucke:

2.55

2
Diese Methode ist insofern gut, als sie eine nachgestellte Null belässt, wenn es nur eine Null gibt. 2,5500 geben also 2,55 zurück und 2.000 geben 2,0 statt 2 zurück. Ideal, wenn Sie
Motorgrößen

4
@ MasonG.Zhwiti Ich habe Zweifel, dass dies mit einigen Dezimalstellen mit mehr Ziffern nach dem Dezimalpunkt wie 232.33220003200 zum Beispiel funktioniert: -)
gotqn

@gotqn Guter Punkt, das scheitert definitiv. Für unseren speziellen Anwendungsfall (Formatieren von Motorgrößen in Autos) funktioniert es jedoch perfekt. :)
Mason G. Zhwiti

wie @gotqn sagte .. es ist fehlerhaft, wenn die Zahl lang ist
Ofear

Dies funktioniert nicht genau für Zahlen wie 0,56000. es wird 56 ergeben. Lustig
Gunjan Shakya


2

Versuche dies :

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

Gibt 20.55


1
REPLACE (TRIM (REPLACE (20.00, "0", "")), "", "0") hinterlässt einen Trailing. => "20."
Keith Sirmons

Es ist perfekt auf meinen Fall anwendbar und scheint die einfachste Lösung zu sein. Daumen & abstimmen!
Oak_3260548

2

Ich hatte ein ähnliches Problem, musste aber auch den Dezimalpunkt entfernen, wenn keine Dezimalstelle vorhanden war. Hier ist meine Lösung, die die Dezimalstelle in ihre Komponenten aufteilt und die Anzahl der Zeichen, die aus der Dezimalzeichenfolge entnommen werden, auf der Länge von basiert die Fraktionskomponente (ohne Verwendung von CASE). Um die Sache noch interessanter zu machen, wurde meine Nummer als Float ohne Dezimalstellen gespeichert.

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

Das Ergebnis ist schmerzhaft, ich weiß, aber ich bin mit viel Hilfe aus den obigen Antworten dort angekommen.


2

Der beste Weg ist, vor dem Konvertieren NICHT in FLOAT oder MONEY zu konvertieren, da die Gefahr eines Genauigkeitsverlusts besteht. Die sicheren Wege können also ungefähr so ​​aussehen:

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

Dabei kann @value eine beliebige Dezimalstelle sein (x, y).


@abatishchev, fn_ ist ein bevorzugtes Präfix für SQL-Funktionen. Präfixe werden in Standard-Codierungs- und Namenskonventionen sowie in Best Practices verwendet. Wir können unsere Präfixe anpassen, aber für Best Practices verwenden wir sp_für gespeicherte Prozeduren, fn_für Funktionen, tblfür Tabellen und so weiter on ... dies ist keine Voraussetzung, aber dies sind bewährte Methoden zum Organisieren unserer Datenbanken.
Japzdivino

@ Japongskie: Entschuldigung, aber nein. Präfixe sind überhaupt nicht erforderlich. Dies ist eigentlich die schlechteste Praxis. Siehe 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 und viele mehr
abatishchev

@abatishchev, oh ich verstehe .. also werde ich dem Schulunterricht nicht mehr folgen .. haha ​​LOL, da dein Link von mdsn kam, danke für diesen, ich werde jetzt meine Best Practice ändern .. :)
japzdivino

2

Ich hatte ein ähnliches Problem, musste nachgestellte Nullen von Zahlen wie trimmen xx0000,x00000,xxx000

Ich benutzte:

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

Code ist der Name des Feldes mit der zu schneidenden Nummer. Hoffe das hilft jemand anderem.


Dieser Kommentar funktioniert gut, wenn Sie eine Version von SQL Server verwenden, die alt genug ist, dass Sie die integrierten Funktionen TRIM oder FORMAT in SQL Server nicht verwenden können.
David Parvin

Ich habe ein Problem mit dieser Antwort gefunden. Wenn der Wert im Feld 'Code' ungefähr '10' ist, wird '1' zurückgegeben. Wenn die Zahl '10 .00 'ist, ignoriert sie meiner Meinung nach auch den Dezimalpunkt.
David Parvin

1

Andere Option...

Ich weiß nicht, wie effizient das ist, aber es scheint zu funktionieren und geht nicht über float:

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

Die mittlere Linie entfernt nachgestellte Leerzeichen, die beiden äußeren entfernen den Punkt, wenn keine Dezimalstellen vorhanden sind


1

Ich musste nachfolgende Nullen auf meinen Dezimalstellen entfernen, damit ich eine Zeichenfolge einer bestimmten Länge mit nur führenden Zahlen ausgeben konnte Nullen

(zB musste ich 14 Zeichen ausgeben, damit aus 142.023400 000000142.0234 wurde),

Ich habe verwendet parsename, reverseund cast as intum die nachgestellten Nullen zu entfernen:

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

(Um dann meine führenden Nullen zu erhalten, könnte ich die korrekte Anzahl von Nullen basierend auf der Länge der obigen Werte replizieren und diese mit der Vorderseite der obigen verknüpfen.)

Ich hoffe das hilft jemandem.


@Protiguous Da es 1 Dezimalpunkt gibt, wird 2.5500 wie <Schemaname> gelesen. <Objektname>. Der zweite Parameter von 2 gibt den Schemanamen zurück, der zweite Parameter von 1 gibt den Objektnamen zurück. Es wird normalerweise wie PARSENAME ('dbo.TableName', 2) verwendet, um dbo zurückzugeben, oder PARSENAME ('dbo.TableName', 1), um TableName zurückzugeben.
Ali

Hallo .. Ich sehe, dass mein Alias ​​in Ihrem Kommentar markiert ist. Keine Ahnung warum?
Protiguous

Die genaue Frage, die Sie mir am 26. Mai 2020 gestellt haben, lautete: "Wie soll PARSENAME hier funktionieren?" Es tut mir leid, dass es so lange gedauert hat, Ihnen zu antworten.
Ali

1

Es ist möglich, führende und nachfolgende Nullen in TSQL zu entfernen

  1. Konvertieren Sie es mit der STR TSQL-Funktion in einen String, wenn nicht mit einem String. Dann

  2. Entfernen Sie sowohl führende als auch nachfolgende Nullen

    SELECT REPLACE(RTRIM(LTRIM(REPLACE(AccNo,'0',' '))),' ','0') AccNo FROM @BankAccount
  3. Mehr Infos im Forum .


4
Ein bisschen hässlich, aber diese Version tötet den Rest '.':REPLACE(RTRIM(REPLACE(REPLACE(RTRIM(REPLACE(X,'0',' ')),' ','0'),'.',' ')),' ','.')
Chris B

1
Seien Sie vorsichtig, wenn die Zahl nicht dezimal ist, werden auch Nullen abgeschnitten. CHARINDEX ('.', @ Number)! = 1 wird das testen.
Muflix

Meine vorherige Dezimalprüfung ist falsch. Hier ist besser: Wählen Sie Len (@Test) - Len (Ersetzen (@Test, 'a', '')) als NumberOfCharacters Explained: tinyurl.com/o4fc8g7 und tinyurl.com/kgzkuqk
Muflix

0

Wie wäre es damit? Angenommen, Daten kommen als @thisData in Ihre Funktion:

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

Wäre dies nicht auch ein Ersatz für die Nullen (Nullen) zwischen den Zahlen? Denken Sie nicht, dass das Ersetzen nur am Ende funktioniert ...
mtk

0

Ich verstehe, dass dies ein alter Beitrag ist, möchte aber SQL bereitstellen, das ich mir ausgedacht habe

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

Versuche dies.

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

0

Am einfachsten ist es, den Wert als FLOAT und dann in einen String-Datentyp umzuwandeln.

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

-1

Versuche dies:

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

Ich bevorzuge die Antwort von @ user1959416 hier besser, da sie die Werte nicht ändert. Ab 2.5550 ergibt Ihre Methode beispielsweise 2.56, während ihre Methode 2.555 zurückgibt.
Mason G. Zhwiti

-1

Ich weiß, dass dieser Thread sehr alt ist, aber für diejenigen, die SQL Server 2012 oder höher nicht verwenden oder die FORMAT-Funktion aus irgendeinem Grund nicht verwenden können, funktioniert Folgendes.

Viele der Lösungen funktionierten auch nicht, wenn die Anzahl kleiner als 1 war (z. B. 0,01230000).

Bitte beachten Sie, dass das Folgende nicht mit negativen Zahlen funktioniert.

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

Gibt 10.012345 bzw. 0.012345 zurück.


-1

Versuche dies:

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

Wenn dieser zurückkehrt 999999, fordert das OP auf, die nachfolgenden Nullen zu entfernen.
Japzdivino

-1

Eine DECIMAL (9,6) -Spalte wird ohne Genauigkeitsverlust in float konvertiert, sodass CAST (... AS float) den Trick ausführt.


@HLGEM: zu sagen, dass Float eine schlechte Wahl für die Speicherung von Zahlen ist und "Float niemals verwenden" ist nicht korrekt - Sie müssen nur Ihre Zahlen kennen, z. B. würden Temperaturmessungen als Floats gut funktionieren.

@abatishchev und @japongskie: Präfixe vor gespeicherten SQL-Prozessen und -Funktionen sind immer noch eine gute Idee, wenn sie nicht benötigt werden. Die von Ihnen erwähnten Links weisen nur an, das Präfix "sp_" nicht für gespeicherte Prozeduren zu verwenden, die Sie nicht verwenden sollten. Andere Präfixe sind in Ordnung, z. B. "usp_" oder "spBob_".

Referenz: "Alle Ganzzahlen mit 6 oder weniger signifikanten Dezimalstellen können ohne Genauigkeitsverlust in einen IEEE 754-Gleitkommawert konvertiert werden": https://en.wikipedia.org/wiki/Single-precision_floating-point_format

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.