Jak przekonwertować zmiennoprzecinkowe na varchar w SQL Server

134

Mam kolumnę typu float z liczbami o różnej długości i próbuję przekonwertować je na varchar.

Niektóre wartości przekraczają maksymalny rozmiar biginta, więc nie mogę zrobić czegoś takiego

cast(cast(float_field as bigint) as varchar(100))

Próbowałem używać liczb dziesiętnych, ale liczby nie są tego samego rozmiaru, więc to też nie pomaga

CONVERT(varchar(100), Cast(float_field as decimal(38, 0)))

Każda pomoc jest mile widziana.

AKTUALIZACJA:

Przykładowa wartość to 2.2000012095022E + 26 .

hgulyan
źródło
cast(float_field as varchar(max))inaczej nie dostaję pytania
Denis Valeev
5
wartość twojego rzutu to 2,2e + 026. Prawdopodobnie nie dostałeś pytania :)
hgulyan

Odpowiedzi:

253

Spróbuj użyć STR()funkcji.

SELECT STR(float_field, 25, 5)

Funkcja STR ()


Kolejna uwaga: to pola po lewej stronie ze spacjami. Jeśli jest to problem połącz z LTRIM:

SELECT LTRIM(STR(float_field, 25, 5))
codingbadger
źródło
3
Mam ************************* . Co to jest? :)
hgulyan
4
@hgulyan - Czy Select LTRIM(Str(float_field, 38, 0))działa dla Twoich danych?
Martin Smith
@Martin Smith, Wydaje się, że działa, ale tak samo jak ułamek dziesiętny, więc nie jestem pewien, czy to jest prawdziwa wartość (ostatnie dziesięć cyfr to zero). Myślę, że utracono prawdziwą wartość. Dziękuję Ci!
hgulyan
2
@hgulyan - ostatnie dziesięć cyfr to zero, ponieważ do tego służy ostatni parametr Strfunkcji. Liczba cyfr po przecinku. Czy przeczytałeś link, który opublikowałem? Zmień zero na 10. Select LTRIM(Str(float_field, 38, 10))
codingbadger
4
Chciałbym, żeby w SSMS było ostrzeżenie "hej, kiedy konwertujesz to błędne pływające pole telefoniczne na tekst, przygotuj się na ładny numer telefonu z notacją naukową! Nie jesteśmy wystarczająco sprytni, aby najpierw ltrim (str)" ...
pkExec
44

Jedyny znaleziony przeze mnie bit zapytania, który zwraca DOKŁADNIE tę samą oryginalną liczbę, to

CONVERT (VARCHAR(50), float_field,128)

Zobacz http://www.connectsql.com/2011/04/normal-0-microsoftinternetexplorer4.html

Inne powyższe rozwiązania czasami zaokrąglają lub dodają cyfry na końcu

AKTUALIZACJA : Zgodnie z komentarzami poniżej i co widzę na https://msdn.microsoft.com/en-us/library/ms187928.aspx :

CONVERT (VARCHAR(50), float_field,3)

Powinien być używany w nowych wersjach programu SQL Server (Azure SQL Database i począwszy od SQL Server 2016 RC3)

adinas
źródło
2
+1 dla @adinas, wartość zmiennoprzecinkowa jest konwertowana tak jak ona, ale z wyjątkiem 0wartości zmiennoprzecinkowej konwertowanej jako 0.0E0. Musiałem przekonwertować pole typu float na varchartak, jak muszę wyświetlać, NAkiedy NULLi 0tak, jak jest. Osiągnąłem to, dodając CASEstwierdzenie w zapytaniu, jak poniżej; CASE WHEN float_field IS NULL THEN 'NA' WHEN float_field = 0 THEN '0' ELSE CONVERT(VARCHAR, float_field, 128) END AS float_As_VChar
fujiFX
2
Zgodnie z dokumentem na temat firmy Microsoft - msdn.microsoft.com/en-us/library/ms187928.aspx , składnia 128 została uwzględniona ze względu na starsze wersje i może zostać wycofana w przyszłej wersji
Mike Turner
1
128 jest przestarzałe, ale wydaje się, że 3 zastępuje go w najnowszych wersjach programu SQL Server.
user3524983
13

jest to rozwiązanie, którego ostatecznie użyłem w sqlserver 2012 (ponieważ wszystkie inne sugestie miały tę wadę, że obcinały część ułamkową lub miały inną wadę).

declare @float float = 1000000000.1234;
select format(@float, N'#.##############################');

wynik:

1000000000.1234

ma to kolejną zaletę (w moim przypadku), ponieważ ułatwia separację tysięcy i lokalizację:

select format(@float, N'#,##0.##########', 'de-DE');

wynik:

1.000.000.000,1234
molekularny
źródło
3

Przydatny temat dzięki.

Jeśli chcesz tak jak ja usunąć ołowiu zero, możesz użyć tego:

DECLARE @MyFloat [float];
SET @MyFloat = 1000109360.050;
SELECT REPLACE(RTRIM(REPLACE(REPLACE(RTRIM(LTRIM(REPLACE(STR(@MyFloat, 38, 16), '0', ' '))), ' ', '0'),'.',' ')),' ',',')
Axel
źródło
2

float ma tylko maks. precyzja 15 cyfr. Cyfry po 15. pozycji są więc losowe, a zamiana na bigint (maks. 19 cyfr) lub dziesiętna nie pomaga.

devio
źródło
Nie rozumiem. Wartość pola to 2.2000012095022E + 26. Jakie jest rozwiązanie? Nie ma?
hgulyan
nie można uzyskać więcej cyfr poprzez konwersję na łańcuch, niż jest cyfr przechowywanych w oryginalnej wartości.
devio
Więc straciłem cyfry po 15. pozycji?
hgulyan
Wystąpił jakiś problem z danymi. Muszę tylko zaktualizować tę wartość za pomocą 15-cyfrowej liczby zmiennoprzecinkowej. Przyjmuję twoją odpowiedź, ponieważ opisuje ona główny problem, jaki miałem z tymi danymi. Dziękuję Ci.
hgulyan
2

Może to pomóc bez zaokrąglania

declare @test float(25)

declare @test1 decimal(10,5)

select @test = 34.0387597207
select @test
set @test1 = convert (decimal(10,5), @test)
select cast((@test1) as varchar(12))


Select  LEFT(cast((@test1) as varchar(12)),LEN(cast((@test1) as varchar(12)))-1)
Atul
źródło
2

Zamień na integerpierwszy, a następnie na string:

cast((convert(int,b.tax_id)) as varchar(20))
Amit Patil
źródło
Spowoduje to usunięcie cyfr po przecinku, jeśli istnieją. Stąd to rozwiązanie nie jest dokładne.
RushabhG,
2

Wypróbuj ten, powinien działać:

cast((convert(bigint,b.tax_id)) as varchar(20))
Kam
źródło
2
SELECT LTRIM(STR(float_field, 25, 0))

jest najlepszym sposobem, aby nie dodawać .0000żadnych cyfr na końcu wartości.

RUBEN
źródło
1

Jeśli używasz funkcji CLR, możesz przekonwertować liczbę zmiennoprzecinkową na ciąg, który wygląda tak samo jak liczba zmiennoprzecinkowa, bez wszystkich dodatkowych zer na końcu.

Funkcja CLR

[Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read)]
[return: SqlFacet(MaxSize = 50)]
public static SqlString float_to_str(double Value, int TruncAfter)
{
  string rtn1 = Value.ToString("R");
  string rtn2 = Value.ToString("0." + new string('0', TruncAfter));

  if (rtn1.Length < rtn2.Length) { return rtn1; } else { return rtn2; }
}

.

Przykład

create table #temp (value float)
insert into #temp values (0.73), (0), (0.63921), (-0.70945), (0.28), (0.72000002861023), (3.7), (-0.01), (0.86), (0.55489), (0.439999997615814)

select value,
       dbo.float_to_str(value, 18) as converted,
       case when value = cast(dbo.float_to_str(value, 18) as float) then 1 else 0 end as same
from   #temp

drop table #temp

.

Wynik

value                  converted                  same
---------------------- -------------------------- -----------
0.73                   0.73                       1
0                      0                          1
0.63921                0.63921                    1
-0.70945               -0.70945                   1
0.28                   0.28                       1
0.72000002861023       0.72000002861023           1
3.7                    3.7                        1
-0.01                  -0.01                      1
0.86                   0.86                       1
0.55489                0.55489                    1
0.439999997615814      0.439999997615814          1

.

Caveat

Wszystkie przekonwertowane ciągi są obcinane do 18 miejsc po przecinku i nie ma na końcu zer. 18 cyfr precyzji nie stanowi dla nas problemu. Ponadto 100% naszych liczb FP (blisko 100 000 wartości) wygląda identycznie jak wartości łańcuchowe, tak jak w bazie danych jako liczby FP.

James L.
źródło
0

Zmodyfikowano nieco odpowiedź Axela, ponieważ w niektórych przypadkach przyniesie to niepożądane rezultaty.

DECLARE @MyFloat [float];
SET @MyFloat = 1000109360.050;

SELECT REPLACE(RTRIM(REPLACE(REPLACE(RTRIM((REPLACE(CAST(CAST(@MyFloat AS DECIMAL(38,18)) AS VARCHAR(max)), '0', ' '))), ' ', '0'),'.',' ')),' ','.')
user2388752
źródło
0
select replace(myFloat, '', '')

z REPLACE () dokumentacji :

Zwraca nvarchar, jeśli jeden z argumentów wejściowych jest typu danych nvarchar; w przeciwnym razie REPLACE zwraca varchar.
Zwraca NULL, jeśli którykolwiek z argumentów ma wartość NULL.

testy:
null ==> [NULL]
1,11 ==> 1,11
1,10 ==> 1,1
1,00 ==> 1
0,00 ==> 0
-1,10 ==> -1,1
0,00001 ==> 1e-005
0,000011 ==> 1,1e- 005

Dinah
źródło
0

Wybierz
rzutowanie (replace (convert (decimal (15,2), acs_daily_debit), '.', ',') As varchar (20))

z acs_balance_details

Eduardo
źródło
0

Na podstawie odpowiedzi Molekularnej:

DECLARE @F FLOAT = 1000000000.1234;
SELECT @F AS Original, CAST(FORMAT(@F, N'#.##############################') AS VARCHAR) AS Formatted;

SET @F = 823399066925.049
SELECT @F AS Original, CAST(@F AS VARCHAR) AS Formatted
UNION ALL SELECT @F AS Original, CONVERT(VARCHAR(128), @F, 128) AS Formatted
UNION ALL SELECT @F AS Original, CAST(FORMAT(@F, N'G') AS VARCHAR) AS Formatted;

SET @F = 0.502184537571209
SELECT @F AS Original, CAST(@F AS VARCHAR) AS Formatted
UNION ALL SELECT @F AS Original, CONVERT(VARCHAR(128), @F, 128) AS Formatted
UNION ALL SELECT @F AS Original, CAST(FORMAT(@F, N'G') AS VARCHAR) AS Formatted;
user8642458
źródło
0

Właśnie natknąłem się na podobną sytuację i byłem zaskoczony problemami z zaokrąglaniem `` bardzo dużych liczb '' prezentowanych w SSMS 17.9.1 / SQL 2017.

Nie sugeruję, że mam rozwiązanie, ale zauważyłem, że FORMAT przedstawia liczbę, która wydaje się poprawna. Nie mogę zasugerować, że zmniejsza to dalsze problemy związane z zaokrąglaniem lub jest przydatne w ramach skomplikowanej funkcji matematycznej.

Dostarczony kod T SQL, który powinien jasno pokazać moje spostrzeżenia, jednocześnie umożliwiając innym testowanie ich kodu i pomysłów, jeśli zajdzie taka potrzeba.

WITH Units AS 
(
   SELECT 1.0 AS [RaisedPower] , 'Ten' As UnitDescription
   UNION ALL
   SELECT 2.0 AS [RaisedPower] , 'Hundred' As UnitDescription
   UNION ALL
   SELECT 3.0 AS [RaisedPower] , 'Thousand' As UnitDescription
   UNION ALL
   SELECT 6.0 AS [RaisedPower] , 'Million' As UnitDescription
   UNION ALL
   SELECT 9.0 AS [RaisedPower] , 'Billion' As UnitDescription
   UNION ALL
   SELECT 12.0 AS [RaisedPower] , 'Trillion' As UnitDescription
   UNION ALL
   SELECT 15.0 AS [RaisedPower] , 'Quadrillion' As UnitDescription
   UNION ALL
   SELECT 18.0 AS [RaisedPower] , 'Quintillion' As UnitDescription
   UNION ALL
   SELECT 21.0 AS [RaisedPower] , 'Sextillion' As UnitDescription
   UNION ALL
   SELECT 24.0 AS [RaisedPower] , 'Septillion' As UnitDescription
   UNION ALL
   SELECT 27.0 AS [RaisedPower] , 'Octillion' As UnitDescription
   UNION ALL
   SELECT 30.0 AS [RaisedPower] , 'Nonillion' As UnitDescription
   UNION ALL
   SELECT 33.0  AS [RaisedPower] , 'Decillion' As UnitDescription

)

SELECT UnitDescription

   ,              POWER( CAST(10.0 AS FLOAT(53)) , [RaisedPower] )                                                             AS ReturnsFloat
   ,        CAST( POWER( CAST(10.0 AS FLOAT(53)) , [RaisedPower] )  AS NUMERIC (38,0) )                                        AS RoundingIssues
   , STR(   CAST( POWER( CAST(10.0 AS FLOAT(53)) , [RaisedPower] )  AS NUMERIC (38,0) ) ,   CAST([RaisedPower] AS INT) + 2, 0) AS LessRoundingIssues
   , FORMAT(      POWER( CAST(10.0 AS FLOAT(53)) , [RaisedPower] )  , '0')                                                     AS NicelyFormatted

FROM Units
ORDER BY [RaisedPower]
Andrzej
źródło