Видаліть кінцеві нулі з десяткових значень у SQL Server


85

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

Але коли я вставляю такі дані, як 123,4567, це стає 123,456700

Як прибрати ці нулі?


Будь ласка, змініть правильну відповідь на відповідь @ Andomar
dangalg

@dangalg: Я впевнений, що це слід робити на рівні презентації. Ось чому я ніколи не змінював прийняту відповідь. Однак після подальших міркувань, я думаю, я повинен прийняти те, що спільнота чітко вказала, яка відповідь є найкращою.
абатищев

Відповіді:


147

Магазин decimal(9,6)зберігає 6 цифр праворуч від коми. Відображати кінцеві нулі чи ні - це рішення щодо форматування, яке зазвичай реалізується на стороні клієнта.

Але оскільки формати SSMS floatне мають нульових нулів, ви можете видалити кінцеві нулі, додавши значення decimala 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

6
Плюс float загалом - дуже поганий вибір для зберігання номерів. Ви отримаєте помилки округлення, оскільки це не точний тип. Ніколи не використовуйте поплавок.
HLGEM

Коментар щодо форматування поплавків без нульових нулів був надзвичайно корисним
Sanjiv Jivan

Хоча я правильно вважаю, що масштаб і точність десяткового знака можуть перевищувати масштаби плаваючого знака, а отже, можуть бути випадки, коли (зі значущим значенням більше 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", що не було тим, чим я займався. Ця відповідь таки привела мене до однієї, яку я міг використати,
Кай Джард,

17
SELECT CONVERT(DOUBLE PRECISION, [ColumnName])

SQL Server 2008 і новіших
версій

що відбувається, коли число виглядає як "123.10705000000"? Я спробував вибрати SELECT CONVERT (ДВОЙНА ТОЧНІСТЬ, 123.10705000000), але це дає мені відповідь "123.107". і я хочу "123.10705" як вихід? Чи є спосіб? Я не хочу використовувати CHARINDEX.
Bhavika Zimbar

16

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

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
SELECT REVERSE(ROUND(REVERSE(2.5500),1))

відбитки:

2.55

2
Цей метод приємний тим, що він залишить кінцевий нуль, якщо є лише нуль. Отже, 2.5500 повертає 2.55, а 2.000 повертає 2.0, а не 2.
Чудово підходить

4
@ MasonG.Zhwiti Я сумніваюся, що це спрацює з деяким десятковим числом з більшою кількістю цифр після десяткової коми, наприклад 232.33220003200, наприклад: -)
gotqn

@gotqn Хороший момент, це точно не вдається. Однак для нашого конкретного випадку використання (форматування розмірів двигуна в автомобілях) це працює ідеально. :)
Мейсон Г. Жвіті

як сказав @gotqn .. глючить, коли номер довгий
Ofear

Це точно не працює для таких чисел, як 0,56000. це дасть 56. Смішно
Гуньджан Шак'я


3

Спробуйте це :

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

Дає 20,55


1
REPLACE (TRIM (REPLACE (20.00, "0", "")), "", "0") залишає вас із кінцевим результатом. => "20."
Кіт Сірмонс,

Він цілком застосовний до мого випадку і здається найпростішим рішенням. Великий палець і проголосуй!
Oak_3260548

Чудове рішення без необхідності перетворення на плаваючу! одна незначна проблема помічена 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

Найкращий спосіб - НЕ конвертувати в FLOAT чи GREEN перед конвертацією через ймовірність втрати точності. Тож безпечні шляхи можуть бути приблизно такими:

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/en-us/library/dd172115(v=vs.100).aspx sqlperformance.com/2012/10/t-sql-queries/sp_prefix dba.stackexchange.com/q/25348/3186 та набагато більше
абатищев

@abatishchev, о, я бачу .. так що я більше не буду стежити за навчанням у школі .. ха-ха LOL, оскільки ваше посилання надійшло від mdsn, дякую за це, я зараз зміню свою найкращу практику .. :)
japzdivino

2

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

Я використав:

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

Код - це назва поля з номером, який потрібно обрізати. Сподіваюся, це допомагає комусь іншому.


Цей коментар добре працює, коли ви використовуєте версію SQL Server, яка досить стара, і ви не можете користуватися функціями TRIM або FORMAT, що вбудовуються в SQL Server.
Девід Парвін

Я знайшов одне питання з цією відповіддю. Якщо значення в полі "код" приблизно на зразок "10", воно поверне "1". Якщо число дорівнює '10 .00 ', я думаю, воно також ігнорує десяткову крапку.
Девід Парвін,

1

Ще один варіант ...

Я не знаю, наскільки це ефективно, але це, здається, працює і не проходить через float:

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

Середня лінія знімає кінцеві пробіли, дві зовнішні видаляють точку, якщо немає десяткових цифр


1

Мені потрібно було видалити кінцеві нулі з моїх десяткових знаків, щоб я міг вивести рядок певної довжини лише з початковими символами нулями

(наприклад, мені потрібно було вивести 14 символів, щоб 142.023400 стало 000000142.0234),

Я використовував parsename, reverseі cast as intдля видалення замикаючих нулів:

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

(Щоб потім отримати свої провідні нулі, я міг би відтворити правильну кількість нулів на основі довжини вищезазначеного та об'єднати це в передній частині вище)

Сподіваюся, це комусь допоможе.


@Protiguous Оскільки є 1 десяткова точка, 2,55500 читається як <ім'я_схеми>. <Ім'я_об'єкта>. Другий параметр 2 повертає ім'я схеми, другий параметр 1 повертає ім'я об'єкта. Зазвичай його використовують як PARSENAME ('dbo.TableName', 2), щоб повернути dbo, або PARSENAME ('dbo.TableName', 1), щоб повернути TableName.
Алі

Привіт .. Бачу, мій псевдонім позначений у вашому коментарі. Я не знаю чому?
Близький

Точне запитання, яке ви задали мені 26 травня 2020 року, було: «Як тут повинен працювати 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'),'.',' ')),' ','.')
Кріс Б

1
Будьте обережні, якщо число не десяткове, воно також буде обрізати нулі. CHARINDEX ('.', @ Number)! = 1 перевірить це.
Muflix

Моя попередня десяткова перевірка помилкова. Ось краще: Виберіть Лен (@Test) - Лен (Замінити (@Test, 'a', '')) Як NumberOfCharacters Пояснюється: tinyurl.com/o4fc8g7 та tinyurl.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

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

Найпростіший спосіб - ПРИЛОЖИТИ значення як 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

-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, ОП просить видалити кінцеві нулі.
japzdivino

-1

ДЕКРАМОВИЙ (9,6) стовпець перетвориться на плаваючий без втрати точності, тому CAST (... AS float) зробить трюк.


@HLGEM: твердження, що float - це поганий вибір для зберігання чисел, а "Ніколи не використовувати float" - неправильно - ви просто повинні знати свої номери, наприклад, вимірювання температури було б чудово, як плаваючі.

@abatishchev та @japongskie: префікси перед SQL-процесами та функціями, що зберігаються, все ще є гарною ідеєю, якщо не потрібні; посилання, про які ви згадали, лише вказують не використовувати префікс "sp_" для збережених процедур, які ви не повинні використовувати, інші префікси чудові, наприклад "usp_" або "spBob_"

Посилання: "Усі цілі числа з 6 або менше значущих десяткових цифр можуть бути перетворені у значення з плаваючою комою IEEE 754 без втрати точності": https://en.wikipedia.org/wiki/Single-precision_floating-point_format

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.