Division operator resulting in large number precision - snowflake-cloud-data-platform

When I divide an integer by a number such as 100.00, I end up with a column with 6+ trailing zeros.
For example, when I am expecting 8600/100.00 to result in a value of 86.00, I instead get 86.000000.
I don't remember this being the case in the past -- did something change? Is there a setting in Snowflake to alter this? I know I can cast the column to a specific precision manually or use a floor function but I'd prefer not to do this for every division operation.

Try this
select round(8600/100.00,2);

Related

Why is this implicit type conversion happening in this COALESCE statement?

Why does Ceiling() change the data type to (38,0) here, losing the precision after the decimal point?
This ONLY happens with Decimal(38, X) as shown below.
Running on Microsoft SQL Server 2016
DECLARE #decimal2 DECIMAL(37,4) = 1.1
SELECT COALESCE(1.1,CEILING(#decimal2))
^this returns 1.1
DECLARE #decimal DECIMAL(38,4) = 1.1
SELECT COALESCE(1.1,CEILING(#decimal))
^this returns 1!!
Ceiling returns an integer, but it should be of the datatype that was passed in. I don't know why this particular issue is caused in the example, but you can overcome it like so:
DECLARE #decimal DECIMAL(38,4) = 1.1
SELECT COALESCE(#decimal,CEILING(#decimal)) --RETURNS 1
SELECT COALESCE(#decimal,CAST(CEILING(#decimal) AS DECIMAL(38,4))) --RETURNS 1.1000
My rule to avoid these types of issues are to always cast different datatypes to a common one.
This behavior is (confusely) explained in the Precision, scale, and Length (Transact-SQL) article from Microsoft Docs.
This is an extract from the article:
The result precision and scale have an absolute maximum of 38. When a result precision is greater than 38, it's reduced to 38, and the corresponding scale is reduced to try to prevent truncating the integral part of a result.
Now, the confusing part would be to understand how is the precision and scale calculated. From my testing, it seems to be using the addition rules. For precision max(s1, s2) + max(p1-s1, p2-s2) + 1 and for scale max(s1, s2). But since precision would go over 38, the difference is taken from the scale to preserve the integrity of the integral part.
This is simply due to the fact that the numeric data type can only hold 38 digits and will fill up the most significant values first so if you say 37,4 it will fill up 37 places to the left of the decimal and keep remaining one to the right.
If you put 38 to the left of the decimal there is no room for decimals regardless of what you put on the right.

Arithmetic overflow error for type int, value = 4957500001.400178

I know that similar questions have been asked again in the past, but I think my case is slightly different. I have a column which has Logarithmic values and I'm trying to invert them using the following formula:
SELECT POWER(10,CAST(9.695262723 AS NUMERIC(30,15)))
Let's say the value 9.695262723 is one of the values of that column.
When trying to run this query I get an Arithmetic overflow error for type int, value = 4957500001.400178.
On the other hand, the same query works fine for smaller values e.g. SELECT POWER(10,CAST(8.662644523 AS NUMERIC(30,15)))
How could I overcome that error and calculate the inverse values of the log10 entries I have? Just for information the greater value that exists in the table (in log10 scale) is 12.27256096.
The problem here is your first input parameter (10) which SQL server will, by default, treat as the datatype int.int has a maximum value of 2^31-1 (2,147,483,647), and the number 4,957,500,001 is far larger than this, so you need to use a bigint:
SELECT POWER(CONVERT(bigint,10),CONVERT(numeric(30,15),9.695262723));
Edit: If you need to retain the decimal places, then use a numeric with a large enough scale and precision, instead of bigint.

dividing a decimal type in SQL Server results in unnecessary trailing zeros

I was performing some simple financial calculations in SQL Server when I discovered some odd behavior. I was trying to convert a string of numbers to a decimal type. While the string did not contain a decimal point, I knew from my specifications that the last 3 positions in the string were supposed to be behind the decimal point.
My first approach was flawed, but went something like this:
select convert(decimal(11,3),89456123/1000) as TotalUnits
This resulted in 89456.000. Performing the division before the cast resulted in the decimal parts being truncated.
So I moved the division operation outside the cast, like this:
select convert(decimal(11,3),89456123)/1000 as TotalUnits
This resulted in an explosion of positions after the decimal point. It returned 89456.12300000
According to my decimal specification, I wanted 11 digits, with 3 of them behind the decimal point. Now I have 13 total digits, with 8 behind the decimal. What happened?
To get what I want, I guess I have to double cast, like this:
select convert(decimal(11,3), convert(decimal(11,3),89456123)/1000)
which gives 89456.123.
It turns out no matter what I divide by, the resulting decimal point explosion is the same. Is the division converting the datatype into a double or something?
My question is this:
Why is this happening, and is there a more elegant way to compensate for it, instead of double-casting to decimal.
EDIT
I found this similar question on SO, but it looks like they are again double-casting.
SQL server does integer arithmetic, to force it to use numeric, you can multiply it by 1.0
No need of using convert twice. This gives 89456.123 with out double convert.
select convert(decimal(11,3),89456123*1.0/1000) as TotalUnits
Why does convert(decimal(11,3),89456123)/1000 end up with 6 decimal places? The rules demand it. numeric division has rather complicated rules about the resulting type.
When you say 1.0 you end up with a numeric with the least scale factors possible to represent this value:
SELECT SQL_VARIANT_PROPERTY(1.11, 'BaseType')
SELECT SQL_VARIANT_PROPERTY(1.11, 'Precision')
SELECT SQL_VARIANT_PROPERTY(1.11, 'Scale')
SELECT SQL_VARIANT_PROPERTY(1.11, 'TotalBytes')
What should you do? I think there is no really elegant solution because of the complicated rules. Any solution I can think of involves rather crazy type inference of intermediate results. I recommend pretty much the same solution that RADAR already gave:
select convert(decimal(11,3), convert(decimal(11, 3), 89456123)/1000) as TotalUnits
The main difference is that I think the *1.0 "trick" used as a short hand for a cast is obfuscating the meaning of the code. If you happen to like it feel free to use it, though.
select convert(decimal(11,3),89456123/CONVERT(decimal(11,3),1000))

Why my result of the operation is rounded down to 0?

I've function in T-SQL:
sum(ar.tothandlingtime)/(60*60*24)
and in my result set I've all 0, because the result of this part of the day. Always is below 0.
I want to continue to work on the results, so I need an accurate result in a form and in a view. How?
It is doing integer division, and thus truncating the decimal.
To get your desired result, try converting one side to a decimal:
CONVERT(decimal(19, 18), SUM(ar.tothandlingtime))/(60*60*24)
Using this lets SQL know to perform decimal-based division.
If you need to, you can also play with the precision and scale of the decimal (read more here: http://msdn.microsoft.com/en-us/library/ms187746.aspx)
Of course, if you don't care about the precision, you can also achieve this by putting .0 after each hard-coded number:
(60.0*60.0*24.0)
For example,
select 5/(60.0*60.0*24.0) -- Result: 0.000057870370
select 5/(60*60*24) -- Result: 0
In my experience, this is generally the quickest way to get it to register as decimal division without explicitly using a CAST or CONVERT. If you were strictly using integer-based column values or aggregate functions, though, you would need to convert it, like in the first example.
You are dividing by an int trying converting that to a decimal. Change it like this
sum(ar.tothandlingtime)/CAST((60*60*24) AS DECIMAL ))

SQL Server adding trailing zeros to result of division

Has anyone encountered the following where when you divide a number in SQL a random number of trailing zeros are appended?...
SELECT 8.95/10 ... results in 0.895000
If you have encountered this, what is the reason for the addition of the zeros?
UPDATE: I am aware that casting the result to FLOAT will remove the 0's
First of all, seeing trailing zeros or anything when querying in SSMS is not because it's something special with the DB engine, but it's always the result of the internal query result formating used for displaying. After all, all numbers are just binary values in some representation that at some point gets translated to strings for displaying.
Anyway, the real reason is because of the datatypes involved, and how SSMS decides to display them. When doing those calculations, SQL Server must decide what datatype the result will be, based on the types of the inputs, and in that particular case it was numeric(7,6). You can easily see the result types by saving the result to a temp table and running sp_columns on that:
SELECT 8.95 AS dividend,10 AS divider,8.95/10 AS result INTO #temp ;
EXEC tempdb..sp_columns '#temp' ;
SELECT * FROM #temp ;
DROP TABLE #temp ;
In my case it returned this (among other uninteresting things for now):
COLUMN_NAME TYPE_NAME PRECISION LENGTH SCALE
dividend numeric 3 5 2
divided int 10 4 0
result numeric 7 9 6
Playing with castings in various places in the division will only change the resulting data types. The interesting fact is the Scale for the result column, note that it's a 6. That's exactly the number of decimal places that SSMS decides to display for the NUMERIC data type, regardless of the actual value. FLOAT don't have this formating from SSMS, which is why the casting eliminates the trailing zeros. Of course, when using the DB from outside SSMS, the formating will depend on the calling application and will not be subject to all this.
As another example of this behavior, just try SELECT CAST(1 AS NUMERIC(18,10)) and see that it shows 1.0000000000.

Resources