BigQuery - ROUND, TRUNC function Issue - google-bigquery

I have a issue with round, trunc function from BigQuery standard query .
I expected at 3953.7, 3053.67, 3053.667. f1_, f2_ result is different. It is a bug??
I expected at 3.195, 3.195, 3.1955, 3.1965, 3.1945.
f1_, f3_ result is different. Is it my fault?

The ROUND() is used to round a numeric field to the nearest number of decimals specified.
There is a limitation of floating point values.
They can only represent binary values, but cannot precisely represent decimal digits after the decimal point (see here).
In case of SELECT ROUND(3053.665,2) you receive: 3053.66, you can overcome it by using: ROUND(value + 0.005, 2), which allows you to receive 3053.67.
Anyway, if you want to take care about precise decimal results, you should use the NUMERIC type. The following query gives results that you expect:
SELECT ROUND(3953.65,1), ROUND(numeric '3053.665',2), ROUND(numeric '3053.6665',3)
TRUNC(), the following query gives results that you expect:
SELECT TRUNC(3.1955,3), TRUNC(numeric'3.195',3), TRUNC(3.1955,4), TRUNC(numeric '3.1965',4), TRUNC(3.1945,4)
BigQuery parses fractional numbers as floating point by default for better performance, while other databases parses fractional numbers as NUMERIC by default. This means the other databases would interpret TRUNC(3.03,2) in the same way BigQuery interprets TRUNC(numeric '3.03',2).
I hope it will helps you.

This is due to the fact that, in BigQuery, digits are stored as floating point values by default.
You can fin more information about how these work in Wikipedia, but the main idea is that some numbers are not stored as they are but as the closest approximation its representation allows. If instead of 3.03 it is internally represented as 3.0299999999..., when you trunc it the result will be 3.02.
Same thing happens with round function, if 3053.665 is internally stored as 3053.6649999999..., the result of rounding it will be 3053.66.
If you specify it to be stored as NUMERIC, it then works as "expected":
select trunc(numeric '3.195', 3)
gives as result 3.195
You can find more information about Numeric Types in the official BigQuery Documentation.

Related

sql - result decimal precision and scale when calculating average

If i have a column with datatype decimal(p,s) what is the standard for expected result's precision and scale when i execute average aggregate.?
i.e result = select avg(decimal(p,s)) from table1;
what is must be the result decimal precision and scale.?
Some links from existing databases like
1. https://docs.oracle.com/javadb/10.6.2.1/ref/rrefsqlj36146.html#rrefsqlj36146
2. https://learn.microsoft.com/en-us/sql/t-sql/functions/avg-transact-sql?view=sql-server-2017
But unable to see any standard followed here. So is there a well accepted standard of this in sql or is it always implementation basis.?
Personally not aware of a standard, have always adjusted based on the level of detail that is required of the column.

data conversion issue

I have a table in which one of field is Real data type. I need to show the values in decimal format like #.###. So i'm converting the real values to decimal. But when i convert for some values it is not generating actual value. For eg:- 20.05 is the actual value. multiple it by 100 and then it to decimal(9,4) it will return like 2004.9999.
select cast(cast(20.05 as real)*100.00 as decimal(9,4))
Why this is returning like this ?
Real or Float are not precise...
Even if you see the value as "20.05", even if you type it in like this, there will be tiny differences.
Your value 2004.9999 (or similar something like 2005.00001) is due to the internal representation of this type.
If you do the conversion to decimal first, it should work as expected:
select cast(cast(20.05 as real) as decimal(9,4))*100.00
But you should really think about, where and why you use floating point numbers...
UPDATE: Format-function
With SQL-Server 2012+ you might use FORMAT() function:
SELECT FORMAT(CAST(20.05 AS REAL)*100,'###.0.000')
This will allow you, to sepcify the format, and you will get text back.
This is fine for presentation output (lists, reports), but not so fine, if you want to continue with some kinds of calculations.

SQL ROUND() function with truncate takes 119.1 and returns 119.09

I have data for pounds and pence stored within concatenated strings (unfortunately no way around this) but can not guarantee 2 decimal places.
E.g. I may get a value of 119.109, so this must translated to 2 decimal places with truncation, i.e. 119.10, NOT 119.11.
For this reason I am avoiding "CAST as Decimal" because I do not want to round. Instead I am using ROUND(amount, 2, 1) to force truncation at 2 decimal places.
This works for the most part but sometimes exhibits strange behaviour. For example, 119.10 outputs as 119.09. This can be replicated as:
ROUND(CAST('119.10' AS varchar),2,1)
My target field is Decimal(19,4) (but the 3rd and 4th decimal places will always be 0, it is a finance system so always pounds and pence...).
I assume the problem is something to do with ROUNDing a varchar....but I don't know anyway around this without having to CAST and therefore introduce rounding that way?
What is happening here?
Any ideas greatly appreciated.
This is due to the way floating point numbers work, and the fact that your string number is implicitly converted to a floating point number before being rounded. In your test case:
ROUND(CAST('119.10' AS varchar),2,1)
You are implicitly converting 119.10 to float so that it can be passed to the ROUND function, 119.10 exactly cannot be stored as a float, proven by running the following:
SELECT CAST(CONVERT(FLOAT, '119.10') AS DECIMAL(30, 20))
Which returns:
119.09999999999999000000
Therefore, when you round this with truncate you get 119.09.
For what it is worth, you should always specify a length when converting to, or declaring a varchar

Formatting real value returned by query from a database

I am using postgresql.The table in my database have column with type REAL.When real value having more than seven zeros postgresql stores it for example as 1e+007.When it is retrieved by query,value return also as 1e+007.But I need the value as 10000000 .What is the solution
You'll have more problems than that if you use floating point numbers for things they aren't suitable for, including pretty much anything where you care about the exact presentation of the number.
I would recommend that you use NUMERIC, a base-10 (decimal) number data type that lets you control precision and scale. See Numeric types. NUMERIC is slower to perform calculations with and consumes more storage so it isn't always the right answer, but it's ideal for a great many applications.
You can use floats, it's just harder because you can't safely compare for exact equality, have to use rounding and formatting functions for display, etc.
Example:
regress=> select '1.2'::float8 - '1.0'::float8;
?column?
----------------------
0.199999999999999956
(1 row)
regress=> select '1.2'::numeric - '1.0'::numeric;
?column?
----------
0.2
(1 row)
Another common solution to problems like these is to use an application defined fixed point representation. If you need (say) 2 decimal places, you just store the number 2000.11 as 200011 in the database, multiplying by 100. This is a common technique in financial applications though it's now more common to use proper decimal data types.
Use SQL CAST. Works for me in DB2
select cast(cast(1e+007 as real) as decimal (15,2)) from sysibm.sysdummy1;
10000000.00
You can set decimal places as per your desired value (15,0).
select to_char(1e+007::real, '9999999999')
More details in the manual: http://www.postgresql.org/docs/current/static/functions-formatting.html

Float type in MySQL

I have a MySQL table with column of type float(10, 6).
If I insert 30.064742 into the column the value stored in the database is 30.064741.
Why?
Floating-point numbers imply a certain amount of imprecision. Use a DECIMAL column if you need to be certain to retain every digit.
It's a general problem with rounding numbers to a precision which can be stored in the database. Floats will round to multiples of powers of two. If you want something that is easier to think about, you can use the Decimal type, which will round to powers of ten.
More details in the documentation for numeric types:
When such a column is assigned a value with more digits following the decimal point than are allowed by the specified scale, the value is converted to that scale. (The precise behavior is operating system-specific, but generally the effect is truncation to the allowable number of digits.)