Say I have a table which has two columns i.e. Quantity and Percentages where my percentages are in decimals. Now I want to multiply these two columns and Round the value down to 2 decimals. Rounding down here means that all the numbers from 1-9 are rounded down. Is there an inbuilt function in SQL to do so as there is in Excel?
Examples:
13.567 should round to 13.56
136.7834 should round to 136.78
0.7699 should round to 0.76
I have tried searching for such a function online but couldn't come across an appropriate solution.
There's a FLOOR function, which can be adapted to your use case:
SELECT FLOOR(value * 100) / 100 AS RoundedValue
You can use TRUNCATE () for this rounddown
select TRUNCATE(2.847, 2) as rounddown
or
SELECT Floor(135.675); //for integer rounding, like 135
You can also use
select round(123.456, 2, 1) as rounddown
The 3rd parameter being non-zero will cause a truncation after the number of decimal points specified in the 2nd parameter.
DB Fiddle
https://www.ibm.com/support/knowledgecenter/en/SSEPEK_10.0.0/sqlref/src/tpc/db2z_bif_truncate.html
https://www.w3schools.com/sql/func_sqlserver_floor.asp
The solution to the problem is to truncate the extra decimal which can be achieved by using the extra parameter of the ROUND function which is ROUND(number, decimal_places, 0/1). Here if the last parameter is anything other than 0, it will truncate the rather than rounding off which is equivalent to the ROUNDDOWN() function of excel that I was looking for.
Alternatively, you can use the TRUNCATE() function, passing the number of decimal places to keep as the second parameter, which will drop off any extra decimals, acting as a ROUNDDOWN() function.
I hope this rounding utility helps somebody:
CREATE FUNCTION `get_round`(val DOUBLE, nDigits INT, RoundStyle VARCHAR(255)) RETURNS double
NO SQL
BEGIN
DECLARE a DOUBLE DEFAULT 0;
SET nDigits = ifnull(nDigits, 0);
CASE
WHEN UCASE(RoundStyle) IN ('ROUND NEAREST','', 'NEAREST', '', 'RND','ROUND', 'DEFAULT','DFLT', null) THEN #normal rounding, but up from 10.50#
SET a = round(val, nDigits);
WHEN UCASE(RoundStyle) IN('ROUND UP', 'UP') THEN #ROUND 10.554 to 10.56
SET a = ceil(val * (power(10, nDigits) )) / (power(10, nDigits));
WHEN UCASE(RoundStyle) IN('ROUND DOWN', 'DOWN') THEN #ROUND 10.555 to 10.55
SET a = truncate(val, nDigits) ;
WHEN UCASE(RoundStyle) IN('ROUND BANKER', 'BANKER','BANKERS ROUNDING') THEN #ROUND TO THE NEAREST EVEN 10.555 is 10.56 and 10.565 is 10.56
SET a = IF(ABS(val - TRUNCATE(val, nDigits)) * POWER(10, nDigits + 1) = 5
AND NOT CONVERT(TRUNCATE(ABS(val) * POWER(10, nDigits), 0), UNSIGNED) % 2 = 1,
TRUNCATE(val, nDigits), ROUND(val, nDigits));
WHEN UCASE(RoundStyle) IN('ROUND UP INTEGER', 'INT UP','UP INT') THEN #10.4 rounds to 11.0
SET a = ceiling(val);
WHEN UCASE(RoundStyle) IN('ROUND DOWN INTEGER', 'INT DOWN','DOWN INT') THEN #10.6 rounds to 10.0
SET a = floor(val);
END CASE;
RETURN ifnull(a, 0);
END
yes there are some Function in sql for round
ex:
SELECT ProductName, Price, FlOOR(Price) AS RoundedPrice
FROM Products;
Problem 1
SELECT
f.MANHOUR_TOTAL,
f.MATERIAL_TOTAL,
e.NILAI_RATE * f.MANHOUR_TOTAL AS LABOUR_TOTAL
Which is the existing data is e.NILAI_RATE = 4.00 and MANHOUR_TOTAL = 11.00. The result is 44.0000.
How to keep two digits behind comma on LABOUR_TOTAL as 44.00
Problem 2, I want to use those LABOUR_TOTAL to next operation like this :
SELECT
f.MANHOUR_TOTAL,
f.MATERIAL_TOTAL,
e.NILAI_RATE * f.MANHOUR_TOTAL AS LABOUR_TOTAL
LABOUR_TOTAL + f.MATERIAL_TOTAL AS FINISHING_TOTAL
But it gives me null value on FINISHING_TOTAL. Is it possible to do like this ? Any help and suggestions is so appreciated.
For Problem 1 you want ROUND:
SELECT ROUND(e.NILAI_RATE * f.MANHOUR_TOTAL, 2) AS LABOUR_TOTAL
should do it!
For Problem 2, consider this:
SELECT
f.MANHOUR_TOTAL,
f.MATERIAL_TOTAL,
ROUND(e.NILAI_RATE * f.MANHOUR_TOTAL, 2) AS LABOUR_TOTAL,
ROUND((e.NILAI_RATE * f.MANHOUR_TOTAL) + f.MATERIAL_TOTAL, 2) AS FINISHING_TOTAL
Why does the following return .500000 rather than .500?
SELECT 50 / CAST(100 AS decimal(3))
Because you are casting the divisor not the result. And you have not specified precision.
See this for examples:
SELECT 50 / CAST(100 AS decimal(3))
,50 / CAST(100 AS decimal(6,3))
,CAST (50 / CAST(100 AS decimal(3)) AS decimal(3))
,CAST (50 / CAST(100 AS decimal(3)) AS decimal(6,3))
Precision, Scale, and Length (Transact-SQL)
Precision is the number of digits in a number. Scale is the number of
digits to the right of the decimal point in a number. For example, the
number 123.45 has a precision of 5 and a scale of 2.
DECIMAL uses a default precision of 18 and scale of 3.
Therefore when you case to DECIMAL(3) you get a DECIMAL(3,0). Then you use it as a divisor and SQL Server follows its rules for the resultant scale.
Operation Result precision Result scale
e1 / e2 p1 - s1 + s2 + max(6, s1 + p2 + 1) max(6, s1 + p2 + 1)
I have a float column with numbers of different length and I'm trying to convert them to varchar.
Some values exceed bigint max size, so I can't do something like this
cast(cast(float_field as bigint) as varchar(100))
I've tried using decimal, but numbers aren't of the same size, so this doesn't help too
CONVERT(varchar(100), Cast(float_field as decimal(38, 0)))
Any help is appreciated.
UPDATE:
Sample value is 2.2000012095022E+26.
Try using the STR() function.
SELECT STR(float_field, 25, 5)
STR() Function
Another note: this pads on the left with spaces. If this is a problem combine with LTRIM:
SELECT LTRIM(STR(float_field, 25, 5))
The only query bit I found that returns the EXACT same original number is
CONVERT (VARCHAR(50), float_field,128)
See http://www.connectsql.com/2011/04/normal-0-microsoftinternetexplorer4.html
The other solutions above will sometimes round or add digits at the end
UPDATE: As per comments below and what I can see in https://msdn.microsoft.com/en-us/library/ms187928.aspx:
CONVERT (VARCHAR(50), float_field,3)
Should be used in new SQL Server versions (Azure SQL Database, and starting in SQL Server 2016 RC3)
this is the solution I ended up using in sqlserver 2012 (since all the other suggestions had the drawback of truncating fractional part or some other drawback).
declare #float float = 1000000000.1234;
select format(#float, N'#.##############################');
output:
1000000000.1234
this has the further advantage (in my case) to make thousands separator and localization easy:
select format(#float, N'#,##0.##########', 'de-DE');
output:
1.000.000.000,1234
SELECT LTRIM(STR(float_field, 25, 0))
is the best way so you do not add .0000 and any digit at the end of the value.
Convert into an integer first and then into a string:
cast((convert(int,b.tax_id)) as varchar(20))
Useful topic thanks.
If you want like me remove leadings zero you can use that :
DECLARE #MyFloat [float];
SET #MyFloat = 1000109360.050;
SELECT REPLACE(RTRIM(REPLACE(REPLACE(RTRIM(LTRIM(REPLACE(STR(#MyFloat, 38, 16), '0', ' '))), ' ', '0'),'.',' ')),' ',',')
float only has a max. precision of 15 digits. Digits after the 15th position are therefore random, and conversion to bigint (max. 19 digits) or decimal does not help you.
This can help without rounding
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)
Try this one, should work:
cast((convert(bigint,b.tax_id)) as varchar(20))
select replace(myFloat, '', '')
from REPLACE() documentation:
Returns nvarchar if one of the input arguments is of the nvarchar data type; otherwise, REPLACE returns varchar.
Returns NULL if any one of the arguments is NULL.
tests:
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
If you use a CLR function, you can convert the float to a string that looks just like the float, without all the extra 0's at the end.
CLR Function
[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; }
}
.
Example
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
.
Output
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
All converted strings are truncated at 18 decimal places, and there are no trailing zeros. 18 digits of precision is not a problem for us. And, 100% of our FP numbers (close to 100,000 values) look identical as string values as they do in the database as FP numbers.
Modified Axel's response a bit as it for certain cases will produce undesirable results.
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'),'.',' ')),' ','.')
Select
cast(replace(convert(decimal(15,2),acs_daily_debit), '.', ',') as varchar(20))
from acs_balance_details
Based on molecular's answer:
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;
I just came across a similar situation and was surprised at the rounding issues of 'very large numbers' presented within SSMS v17.9.1 / SQL 2017.
I am not suggesting I have a solution, however I have observed that FORMAT presents a number which appears correct. I can not imply this reduces further rounding issues or is useful within a complicated mathematical function.
T SQL Code supplied which should clearly demonstrate my observations while enabling others to test their code and ideas should the need arise.
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]