Mysql CAST return invalid data - mysql

I have a query
SELECT MAX(CAST(user_name as SIGNED)) as max_id FROM (`users`)
it returns
2.01303045556E+12
but actually the maximum value is 2013030455555
Anybody know how it happens??

That is correct.
2.01303045556E+12 actually IS 2013030455555.
x E+12 means x*10 ^ 12
2*10^12=2000000000000 (2 followed by 12 zeros).
This is expotential (usually floating point) number representation. See Scientific notation at wikipedia (scroll down to "E notation").
To get rid of it you may cast that data to decimal or integer, instead of float. Maybe there are better methods, but I dont know them.
Example:
-- example for 16 digits
SELECT MAX(CAST(user_name as DECIMAL(16,0)) as max_id FROM (`users`)
Another solution: change format of the number in SQL or maybe PHP if you are using it.

Related

SQL avg then trailing numbers

I'm trying to get the average number, and then remove the trailing, pointless zeros afterwards, (new to SQL) but I can't understand why it wont remove them, do I have the wrong idea??
So far I have;
SELECT total,
AVG(total(TRUNCATE(total/1,2))
I think you are looking for cast as below.
select cast(17.800000 as dec(3,1))
Result:
val
----
17.8
so you query will be
SELECT total, cast(AVG(total) as dec(3,1))
considering you just need 2 digit before . If you need more digits, you can adjust it accordingly.
DEMO
Assuming you are using SQL Server then you can cast the answer to a decimal with one decimal point:
select cast(avg(total) as decimal(9,1))
This SQLFiddle shows it: link
SELECT
TRUNCATE(AVG(myFloat), 2),
AVG(myFloat),
ROUND(AVG(myFloat), 2)
FROM docs
You should probably use ROUND instead of TRUNCATE.
The stuff after the decimal is odd because of floating point math, and there are occasions where floating point math is internally calculated as .009999999 instead of .01000000000
I believe these answers that use a CAST may have the same truncation problem.
You simply want to avoid casting or truncation when you are removing the decimal places beyond what you're interested in. Be explicit in what you are doing and less mistakes will pop up later.

How to know the number of positions on the right of the decimal point in a float?

I'm preparing some mapping sheets for migrating an actual MYSQL database to a new ORACLE one. Some of the data are defined as float, but I would like to know exactly the length of the value in the column having the maximum decimals after the point. This would help me to restrict the data type instead of declaring it as a NUMBER.
Is there an easy way to do this in MySQL? I've tried with a regular expression but it does not match all values (I've found a value like 7.34397493274) but the following regex does not retrieve it:
SELECT column
from `db`.`table`
where column REGEXP '^-?[0-9]+\.[0-9]{7,}$' =1;
Thanks
You are going down the wrong track. There is no convenient answer to "how many digits are to the right of the decimal point in a floating point number". There is an answer to the "precision" of a floating point number. That is 23. The relationship between precision and the numbers to the right of the floating point number depends on the scale factor.
You might want to review the documentation entitled Problems with Floating Point Numbers.
More concretely, the problem is that a particular number might be represented as:
1.200000000001
or
1.199999999997
(I'm not saying these are actual representations, just examples.) What value would you give for the numbers to the right of the decimal point? By representing the values as floats, the database has lost this information.
Instead, you have several options:
Just use NUMBER, which is generally a reasonable type.
Use BINARY_FLOAT, which would be the same type.
Understand the application to figure out how many decimal points are actually needed.
Play games with the representation, looking for strings of zeros and nines (say four in a row) and assume they are not significant.
If you are looking to find the length after the decimal point then in mysql you can use substring_index and length function together as
mysql> select length(substring_index('7.34397493274','.',-1)) as len;
+-----+
| len |
+-----+
| 11 |
+-----+
1 row in set (0.00 sec)

Performing bitwise operations on large bit strings in MySQL?

I've got a MySQL database with a large amount of 2048-bit binary strings (e.g '0111001...0101'). One calculation I'll need is the Hamming Distance (the total count of 1's in the XOR'd result) of these strings compared to some externally generated bitstring. In order to get an idea of how to write this query, I tried writing it for smaller bitstrings. Here's an example:
select BIT_COUNT(bin((b'0011100000') ^ (b'1111111111')))
The inner portion that computes the XOR works correctly, but BIT_COUNT returns strange results. This example returns 14, which is longer than the string itself.
So I have a few questions:
First, why is BIT_COUNT returning such strange results. Is it operating on a string rather than the binary string I'd like it to operate on? If so, how do I deal with this?
Second, notice that I'm casting (is that the right word here?) the strings as binary by prepending with a b. How would I do this with column names and variables? Clearly I can't simply prepend a b to a variable name, and I can't insert a space between. Any ideas?
Thanks,
EDIT:
So here's a solution to the first problem:
select BIT_COUNT(b'0011100000' ^ b'1111111111')
There seems to be a problem when using this for larger strings (2048 bits). I tried:
select BIT_COUNT(b'001110...00011')
and it gives me results like 28, when the actual bitcount should be around 1024. If I remove the b, then it appears to max-out at 64. Any ideas on how to resolve this problem?
Just remove bin function. With it BIN_COUNT treats its argument as a chars string, not as a set of bits. So
select BIT_COUNT(b'0011100000' ^ b'1111111111')
will do the work

Decimal places in SQL

I am calculating percentages. One example is coming down to 38589/38400
So the percentage is 100*(38589/38400) which equals something like 100.4921875, but the result shows up as 100.
How can I get it to be displayed with x number of decimals?
Similarly, will the same work if i'd like 2 to be displayed as 2.000000?
Thanks!
You can cast it to a specific data type, which preserves the data type as well as rounding to a certain precision
select cast(100*(38589/38400) as decimal(10,4))
FYI
select 100*(38589/38400)
# returns 100.4922, not 100 for me
select cast(2 as decimal(20,6))
# output : 2.000000
With regards to your number formatting have you looked at the format function:
mysql> SELECT FORMAT(12332.123456, 4);
-> '12,332.1235'
mysql> SELECT FORMAT(12332.1,4);
-> '12,332.1000'
mysql> SELECT FORMAT(12332.2,0);
-> '12,332'
so to get 2.000000 from 2 do:
SELECT FORMAT(2,6);
Also, according to mySQL's documentation regarding division:
In division performed with /, the
scale of the result when using two
exact-value operands is the scale of
the first operand plus the value of
the div_precision_increment system
variable (which is 4 by default). For
example, the result of the expression
5.05 / 0.014 has a scale of six decimal places (360.714286).
These rules are applied for each
operation, such that nested
calculations imply the precision of
each component. Hence, (14620 /
9432456) / (24250 / 9432456), resolves
first to (0.0014) / (0.0026), with the
final result having 8 decimal places
(0.60288653).
This would lead me to agree with #Cyberwiki regarding the result you would see from your division.
You need to convert one of the types to floating point:
SELECT 100.0 * ((338589 * 1.0)/38400) ...
With regards to the reason why the result shows 100 instead of 100.4921875 is maybe related to the type of the corresponding column assuming that you store the result in a table column. Make sure that the type of that column is Double.
If you'd like 2 to be displayed as 2.000000, just multiply it by 1.0 as follows:
(select (100*(38589/38400*1.0))
and the output will show: 100.49219

Rounded numbers returned as '0.999999999992345' sometimes

I have a report that should return something along the lines of
SELECT brand, ROUND(SUM(count * price) / SUM(count), 2)
WHERE ... GROUP BY brand, ...;
The problem is, I sometimes get 9990.32999999999992345 in my perl code instead of 9990.33 which direct SQL request returns.
The number starts looking that way right after fetchrow_hashref, if it ever does. The same number can come in 'good' or 'bad' form in different queries, but always the same way in any specific query.
How can I track this down?
Read all about floating point accuracy problems here: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
As mellamokb said, you have to round your floating-point numbers. More importantly, count and price probably means that you are calculating the price of something. As this page explains for the FLOAT and DOUBLE datatype, calculations are approximate while for DECIMAL they are exact. For your particular example, the chance is low that will give problems but not if you do a lot of calculations with your price. The usual rule is to always use exact datatypes for calculating prices.
Always round floating point numbers when displaying them on the screen. And do it as the final step as it is displayed. Any intermediate operation has the potential to cause problems like this.
I can think of a couple of causes of this, but first:
Does it make any difference to put a CONCAT( '', ... ) around your ROUND? What version of perl are you using? What does perl -V:nvtype report?
33/100 is a periodic number in binary just like 1/3 is a periodic number in decimal.
$ perl -e'printf "%.20f\n", 0.33'
0.33000000000000001554
Therefore, it would take infinite storage to store it as a floating point number. To avoid the problem, you'll need to store the number as a string, either early (in the query before it's a float) or late (by rounding).
It's an issue inherent with floating point numbers. It's a design feature, not a flaw.
Make sure the value returned from the database is not a floating point value, but a string or decimal. (If the data types of `price` and `count` are both DECIMAL, then the resulting expression should be DECIMAL.
If either of those is a floating point, then you can convert to DECIMAL...
SELECT brand, CONVERT( SUM(count * price) / SUM(count), DECIMAL(18,2) )
WHERE ... GROUP BY brand, ...;
Or convert to a string
SELECT brand, CONVERT(CONVERT( SUM(count * price) / SUM(count), DECIMAL(18,2)),CHAR)
WHERE ... GROUP BY brand, ...;
You can let the conversion to DECIMAL do the rounding for you. If you return a DECIMAL or VARHCAR to Perl, that should avoid floating point issues.
More generally, to handle representation (rounding) of floating point in Perl, you can format using the sprintf function, e.g.
my $rounded_val = sprintf(%.2f, $float_val);