MsSQL FLOOR CEILING issue? Or is there an explanation about that? - sql

anyone can try this in MsSQL:
select floor(4.7000000000000000000000000000000000000)+0.5
I get this result: 5 (!!) But should be 4.5 !?
Or try again with:
select floor(4.70 * 0.25000 * 0.2440 * 5.6325 * 3.0542 * 2.345 * 2.35 * 3.253 )+0.5
The result is 89!! But should be: 88.5 ?!
Is this an issue? Or is there an explanation about that?
(the same problem with CEILING)
Thank you all!

Per the documentation of FLOOR:
-- Syntax for SQL Server, Azure SQL Data Warehouse, Parallel Data Warehouse
FLOOR ( numeric_expression )
Return Types
Returns the same type as numeric_expression.
The problem with this is that it's not true. It preserves the base type, but in case of a decimal type, the scale is reduced to 0:
SELECT
SQL_VARIANT_PROPERTY(4.00, 'precision') AS [precision]
SQL_VARIANT_PROPERTY(4.00, 'scale') AS scale,
Result: precision 3, scale 2.
SELECT
SQL_VARIANT_PROPERTY(FLOOR(4.00), 'precision') AS [precision],
SQL_VARIANT_PROPERTY(FLOOR(4.00), 'scale') AS scale
Result: precision 3, scale 0. This becomes a problem as soon as your decimal hits the maximum precision:
SELECT
SQL_VARIANT_PROPERTY(4.7000000000000000000000000000000000000, 'precision') AS [precision]
SQL_VARIANT_PROPERTY(4.7000000000000000000000000000000000000, 'scale') AS scale,
Precision 38, scale 37. But FLOOR turns this into precision 38, scale 0, and
SELECT CONVERT(DECIMAL(38, 0), 4) + 0.5
results in 5, per the rules for precision and scale when adding decimals: the result of this should be a decimal(40, 1), but as that exceeds the maximum precision, the scale is reduced to preserve as many digits in front of the period as possible, giving us a decimal(38, 0) again: 5.
Conversely, there's no problem with this:
SELECT 4.0000000000000000000000000000000000000 + 0.5
The result of this is a DECIMAL(38, 37), which can hold 4.5000000000000000000000000000000000000 exactly.
The moral: be aware of this scale-eliminating aspect of FLOOR (and CEILING) and reduce the precision as necessary so the scale doesn't get reduced due to overflow:
SELECT CONVERT(DECIMAL(3, 0), FLOOR(4.70 * 0.25000 * 0.2440 * 5.6325 * 3.0542 * 2.345 * 2.35 * 3.253)) + 0.5
Yields 88.5.

Related

remove decimal Place in SQL

Code :
days_between("Created Time","Locked Time")*24
Result table :
Avg Response time (Hours)
2.91
6.00
9.13
3.65
1.17
0.00
0.77
32.47
The table above is the result i get after the code but currenlty I want to remove all decimal place right before i get this result with the days_between("Created Time","Locked Time")*24 i am using, So how can I do this. I tried to use cast and round () but is not working. Can someone help out. Thank you
Try code:
days_between("Created Time","Locked Time")*24 , 0) AS INT ) AS Response_Time
According to your sample data I guess:
with t(d) as (
values (2.91), (6.00), (9.13), (3.65), (1.17), (0.00), (0.77), (32.47)
)
select d, cast(d/24 as decimal(5,2)) from t;
I have a similar query running on MSSQL, and I can do it as:
SELECT TOP 10 a.SizeBytes AS originalValue
,COALESCE(a.SizeBytes, 0.00) / (1024 * 1024) AS defaultOperation
,CAST(COALESCE(a.SizeBytes, 0.00) / (1024 * 1024) AS INT) AS withCast
,FLOOR(COALESCE(a.SizeBytes, 0.00) / (1024 * 1024)) AS withFloor
,ROUND(COALESCE(a.SizeBytes, 0.00) / (1024 * 1024), 0) AS withRound
FROM filesUploaded a
WHERE a.SizeBytes > 0
Resulting in:
Note that I limited my query to the top 10, for speed generating this example, as my table contains millions of rows.
Also my starting value is integer, so I had to add the decimals in order to be able to see decimals. Probably you don't need to do that as the average should already have decimals, but in my case just dividing returned an integer result for the division without using the COALESCE before dividing.

Teradata Arithmetic operations

In Teradata when computing a percentage (see example below), I get 0 as an answer because Terada rounds results based on the number of decimal places the number have. to my knowledge I have found 2 possible solution to avoid the zero value return.
1- define the decimal number in table with a larger scale value. e.g decimal(18,4) instead of decimal(18,2)
2- cast the first arithmetic operation that occurs to a decimal number with a larger scale value. e.g. select (cast(2.0 as decimal(10,6)) / 10.0) * 100;
has anyone encounter this problem before and what is the solution you went with to solve the problem? thank you in advance.
these are the actual values and the correct answer should be 0.25
select ((28.97 + 28.97) / (11586.87 + 11586.87)) * 100
,(cast((28.97 + 28.97) as decimal(20,4)) / (11586.87 + 11586.87)) * 100
,((cast(28.97 as decimal(18,4)) + 28.97) / (11586.87 + 11586.87))
,(100 * (28.97 + 28.97) / (11586.87 + 11586.87))
,(28.97 + 28.97) , (11586.87 + 11586.87);

How to make SQL query result show with 2 Decimals

I've stumbled into an issue to get this code to show results with only 2 decimals
SELECT
SUM(CAST(
Size * 8 as Decimal)/1024
) as [Size in MB]
FROM
sysfiles
As for now it returns the size of my database with 7 decimals :/
I would advise converting to a decimal format with two places:
select convert(decimal(20, 2), size * 8.0/1024) as [Size in MB]
from sysfiles;
This converts the value to the right type. However, if you want to ensure that the value is displayed to the right precision/scale, then you can use format() or str():
select str(size * 8.0/1024, 20, 2) as [Size in MB]
from sysfiles;
You can cast decimal with just cast(xxx as decimal({length},{precision}))
SELECT
SUM(CAST(
Size * 8 as Decimal(20,2))/1024
) as [Size in MB]
FROM
sysfiles
just cast the sum itself to decimal
SELECT CAST(SUM(CAST(Size * 8 AS DECIMAL(18,2)) / 1024) AS DECIMAL(18,2)) [Size in MB]

decimal point issue once again

The first line of code displays to 2 decimal points
The second line displays to 3 decimal points
SUM(CONVERT(DECIMAL(8,2),[can]/1.2)) + SUM(CONVERT(DECIMAL(8,2),[carton]/1.2)) AS [N],
(SUM(CONVERT(DECIMAL(8,2),[can]/1.2)) + SUM(CONVERT(DECIMAL(8,2),[carton]/1.2)))*0.2 AS [V]
Can someone please tell me how to get the second line to show 2 decimal points
If you want to control the display, the do the cast to decimal after the calculation:
CONVERT(DECIMAL(8, 2), SUM([can]/1.2)) + SUM([carton]/1.2)) AS [N],
You can do the conversion before, if you have a need to represent the some intermediate value as a decimal. Do note, though, that SQL Server has quite arcane rules for the precision and scale of intermediate and final results when doing decimal arithmetic.
Just cast the result to a 2 decimal place decimal:
select --just added to make the example runnable
SUM(CONVERT(DECIMAL(8,2),[can]/1.2)) + SUM(CONVERT(DECIMAL(8,2),[carton]/1.2)) AS [N],
CONVERT(DECIMAL(8,2), --add this line
(SUM(CONVERT(DECIMAL(8,2),[can]/1.2)) + SUM(CONVERT(DECIMAL(8,2),[carton]/1.2)))*0.2
) --and an additional close bracket
AS [V]
from (select 1.0 [can], 1.0 [carton] union all select 2.0, 3.0) x --just added to make the example runnable
The reason you're seeing 3 decimal places is because that's what the result of the calculation is; and when working with decimals SQL will output a decimal of the appropriate precision and scale to hold that result, unless you cast/convert it to something specific.
You convert to 2 decimals using CONVERT...
SELECT
SUM(CONVERT(decimal(8, 2), [can] / 1.2)) + SUM(CONVERT(decimal(8, 2), [carton] / 1.2)) AS [N],
CONVERT(decimal(8, 2), ((SUM(CONVERT(decimal(8, 2), [can] / 1.2)) + SUM(CONVERT(decimal(8, 2), [carton] / 1.2))) * 0.2)) AS [V]

T-SQL - how to round DOWN to nearest .05

The database I am using is SQL Server 2005. I am trying to round values DOWN to the nearest .05 (nickel).
So far I have:
SELECT ROUND(numberToBeRounded / 5, 2) * 5
which almost works - what I need is for the expression, when numberToBeRounded is 1.99, to evaluate to 1.95, not 2.
Specify a non-zero value for a third parameter to truncate instead of round:
SELECT ROUND(numberToBeRounded / 5, 2, 1) * 5
Note: Truncating rounds toward zero, rather than down, but that only makes a difference if you have negative values. To round down even for negative values you can use the floor function, but then you can't specify number of decimals so you need to multiply instead of dividing:
SELECT FLOOR(numberToBeRounded * 20) / 20
If your data type is numeric (ISO decimal) or `money, you can round towards zero quite easily, to any particular "unit", thus:
declare #value money = 123.3499
declare #unit money = 0.05
select value = value ,
rounded_towards_zero = value - ( value % #unit )
from #foo
And it works regardless of the sign of the value itself, though the unit to which you're rounding should be positive.
123.3499 -> 123.3000
-123.3499 -> -123.3000