i have table called 'test' and want to calculate based on different codes, most of them should be saved in 5 decimals except certain code, like containing jpy in 3 decimals, and xua in 2 decimals
create table test(
id int, ymd date,
code varchar(10),
price int
)
insert into test(id, ymd, code, price) values
(1, '2019-01-01', 'auus', 75125),
(2, '2019-01-02', 'nzus', 68541),
(3, '2019-01-03', 'xuaus', 131485),
(4, '2019-01-04', 'aujp', 77852),
(5, '2019-01-05', 'usjp', 110852),
(6, '2019-01-06', 'xuaus', 131091)
So my execute code is:
select id, ymd, code, price,
case
when code like '%xua%' then round(price/100,2)
when code like '%jp%' then round(price/1000,3)
else round(price/100000,5)
end as t
from test
ideal result:
id ymd code price t
1 2019-01-01 auus 75125 0.75125
2 2019-01-02 nzus 68541 0.68541
3 2019-01-03 xuaus 131485 1314.85
4 2019-01-04 aujp 77852 77.852
5 2019-01-05 usjp 110852 110.852
6 2019-01-06 xuaus 131091 1310.91
intersting, above sql works well with Mysql, but i am using mariadb, and just can't get results as same as mysql, spent 2 days to fix problem, but still don't know, please help
mysql> select id, ymd, code, price,
-> case
-> when code like '%xua%' then round(price/100,2)
-> when code like '%jp%' then round(price/1000,3)
-> else round(price/100000,5)
-> end as t
-> from test ;
+------+------------+-------+--------+------------+
| id | ymd | code | price | t |
+------+------------+-------+--------+------------+
| 1 | 2019-01-01 | auus | 75125 | 0.75125 |
| 2 | 2019-01-02 | nzus | 68541 | 0.68541 |
| 3 | 2019-01-03 | xuaus | 131485 | 1314.85000 |
| 4 | 2019-01-04 | aujp | 77852 | 77.85200 |
| 5 | 2019-01-05 | usjp | 110852 | 110.85200 |
| 6 | 2019-01-06 | xuaus | 131091 | 1310.91000 |
+------+------------+-------+--------+------------+
6 rows in set (0.04 sec)
Using FORMAT instead of ROUND:
mysql> select id, ymd, code, price,
case when code like '%xua%' then format(price/100,2)
when code like '%jp%' then format(price/1000,3)
else format(price/100000,5) end as t from test;
+------+------------+-------+--------+----------+
| id | ymd | code | price | t |
+------+------------+-------+--------+----------+
| 1 | 2019-01-01 | auus | 75125 | 0.75125 |
| 2 | 2019-01-02 | nzus | 68541 | 0.68541 |
| 3 | 2019-01-03 | xuaus | 131485 | 1,314.85 |
| 4 | 2019-01-04 | aujp | 77852 | 77.852 |
| 5 | 2019-01-05 | usjp | 110852 | 110.852 |
| 6 | 2019-01-06 | xuaus | 131091 | 1,310.91 |
+------+------------+-------+--------+----------+
6 rows in set (0.00 sec)
mysql> select ##version;
+----------------------------------------+
| ##version |
+----------------------------------------+
| 10.3.11-MariaDB-1:10.3.11+maria~bionic |
+----------------------------------------+
1 row in set (0.00 sec)
Note that it includes a "thousands-separator" when appropriate. See the 3rd argument to FORMAT() or the Locale setting to change that.
I suspect it is the display process that is formatting the output differently. By switching from ROUND to FORMAT, I managed to get MariaDB's output to be nearly the same as MySQL's. The remaining difference is the added commas ("thousands separators"), which may show as '.' for some Locales.
In contrast, for MySQL 5.6.22:
+------+------------+-------+--------+---------+
| id | ymd | code | price | t |
+------+------------+-------+--------+---------+
| 1 | 2019-01-01 | auus | 75125 | 0.75125 |
| 2 | 2019-01-02 | nzus | 68541 | 0.68541 |
| 3 | 2019-01-03 | xuaus | 131485 | 1314.85 |
| 4 | 2019-01-04 | aujp | 77852 | 77.852 |
| 5 | 2019-01-05 | usjp | 110852 | 110.852 |
| 6 | 2019-01-06 | xuaus | 131091 | 1310.91 |
+------+------------+-------+--------+---------+
The numeric values are the same, but the display is different. The difference seems to come from the commandline tool mysql, not from ROUND, itself. Note that t is right-justified, implying that the values are seen as numeric.
If this offends someone enough, file a bug report with MariaDB.
77.75200000000001 -- This is representative of some intermediate computation using DOUBLE instead of all DECIMAL. MySQL (and MariaDB) do a reasonably good job of second-guessing where the number are headed. And usually they get away with whatever is done.
In DOUBLE, 77.75200000000001 is not exactly equal to the DECIMAL 77.752 because one is binary, one is decimal. For this reason, I often recommend not using FLOAT or DOUBLE for "money".
Assuming your real goal is to represent a monetary value as 77.7520000000000000000000000..., that is exactly '77.752', and, assuming you need at most 5 decimal places for the various values, I recommend you do this:
t DECIMAL(m, 5)
where m is a suitably large number for any values you may eventually have. For the numbers given, (9,5) will suffice, but I suspect you should do more like DECIMAL(14,5) to allow for a billion dollars/euros/yen/etc.
What I don't know is where in the processing DOUBLE crept in.
Latest 'advice'
Use DECIMAL(14,5) for all monetary values in your system, not INT.
14,5 lets you get up to a billion 'dollars'; change that as needed for your expected max value.
Ignore my comments about FORMAT(); it seems to be too confusing.
Get rid of the CASE clause, at least for that particular usage.
Most arithmetic among DECIMAL values will be exact, and not encounter 77.75200000000001. If it crops up again, start a new Question and include all the steps, datatypes, etc, involved in the computation.
The above notes refer to storing and computing. For displaying, please specify the requirements:
Plan A: 5 decimal places is OK.
Plan B: need to round to 3 or 2 decimals for some values.
Plan C: You have application code, not in SQL, that can deal with the issue.
Plan D:...
i have a table like this with a var char field reference_number
actually i need to get the max of number in that field
<<student>>
|`id` | `reference_number`(varchar(25))
--------------------------
| 1 | L250
| 2 | SP521
| 3 | S120
| 4 | SP500
| 5 | S122
the desired result is 521 because if we are avoiding the non numeric value then it will come like this
|`id` | `reference_number`
--------------------------
| 1 | 250
| 2 | 521
| 3 | 120
| 4 | 500
| 5 | 122
how to get the the value 521 from the table
I assume you have extracted 'reference_number' as shown in the second snippet from the first snippet. if so, try :::
select max(cast (reference_number as int)) from student
In order to get the number 521 (and all the numbers from the reference_number column) you could try:
SELECT *
FROM yourtable
WHERE reference_number REGEXP '^[0-9]+$';
And then you can add an order by statement.
I have ipv6 addresses stored in decimal(39,0) unsigned format.
I need to query the database. I'm using INET6_ATON() which converts ipv6 to binary. Now I need to convert that binary to decimal(39,0).
Is this possible in pure MySQL?
Yes, is possible. Because DECIMAL representation of IPv6 is bigger than maximum 64-bit integer (18,446,744,073,709,551,615), you must split the 'string' up to 16 characters and then to join them together:
example table:
mysql> select * from ip_table;
+----+-----------------------------------------+
| id | ipv6 |
+----+-----------------------------------------+
| 1 | 2001:db8:a0b:12f0::1 |
| 2 | 3731:54:65fe:2::a7 |
| 3 | FE80:0000:0000:0000:0202:B3FF:FE1E:8329 |
| 4 | FE80::0202:B3FF:FE1E:8329 |
+----+-----------------------------------------+
4 rows in set
SQL statement:
select id,
(
cast(conv(substr(HEX(INET6_ATON(t.`ipv6`)), 1, 16), 16, 10) as decimal(65))*18446744073709551616 +
cast(conv(substr(HEX(INET6_ATON(t.`ipv6`)), 17, 16), 16, 10) as decimal(65))
) as converted
from ip_table t
result:
+----+-----------------------------------------+
| id | converted |
+----+-----------------------------------------+
| 1 | 42540766414390830568948465903729639425 |
| 2 | 73361969000969283948743196392239923367 |
| 3 | 338288524927261089654163772891438416681 |
| 4 | 338288524927261089654163772891438416681 |
+----+-----------------------------------------+
4 rows in set
Note that last two IPs are the same, I've put them in different format in order to test is the script works properly.
I have inserted diff values of pi (see below):
3.14
3.1415
3.14159
3.14159265359
I do not see the different in how the different floating point types handle the same values.
Code:
mysql> select * from test_types;
+---------+---------+---------+----------+
| flo | dub | deci | noomeric |
+---------+---------+---------+----------+
| 3.14000 | 3.14000 | 3.14000 | 3.14000 |
| 3.14150 | 3.14150 | 3.14150 | 3.14150 |
| 3.14159 | 3.14159 | 3.14159 | 3.14159 |
| 3.14150 | 3.14150 | 3.14150 | 3.14150 |
| 3.14159 | 3.14159 | 3.14159 | 3.14159 |
+---------+---------+---------+----------+
5 rows in set (0.00 sec)
mysql> describe test_types;
+----------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------------+------+-----+---------+-------+
| flo | float(10,5) | YES | | NULL | |
| noomeric | decimal(10,5) | YES | | NULL | |
| deci | decimal(10,5) | YES | | NULL | |
| dub | double(10,5) | YES | | NULL | |
+----------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
I can see here that when creating the table the field with numeric type used DECIMAL (see describe command table).
Does anybody know an example showing differences between FLOAT, DECIMAL and DOUBLE please?
FLOAT and DOUBLE are meant for very small values or very large values.
Essentially they are the same thing (except differ in storage size FLOAT 4 bytes against DOUBLE 8 bytes, see Data Type Storage Requirements)
The main thing about them is that they are approximate (see quoted from Oracle website):
Because floating-point values are approximate and not stored as exact
values, attempts to treat them as exact in comparisons may lead to
problems. They are also subject to platform or implementation
dependencies.
DECIMAL allows for an exact representation but the reason your DECIMAL column did not work for PI very well is because you allowed for only 5 decimal places but then you fed it 11 decimal places.
The best way to store the value of PI accurate to 11 decimal places is something like DECIMAL(12,11).
For an actual example for values being treated differently when stored as DECIMAL as opposed to same value being stored and used as a FLOAT see below:
CREATE TABLE decimal_vs_float_test
( dec DECIMAL(12,11)
, fl FLOAT
);
INSERT INTO decimal_vs_float_test VALUES
( 3.947947949 , 3.947947949 )
,( 3.777777777 , 3.777777777 )
,( 3.555555555 , 3.555555555 )
,( 3.333333333 , 3.333333333 )
,( 3.111111111 , 3.111111111 )
;
SELECT * FROM decimal_vs_float_test WHERE fl = dec
Now you can see the values for a DECIMAL or a FLOAT treated differently.
Hope that helps.
Additionally FLOAT and DOUBLE are floating binary point types whereas DECIMAL is a floating decimal point type.
See this answer for more exact details on what that means, the difference between how the types are encoded and when is best to use what type (its meant for C# but its still interesting).
I have a table of prices.
Each price is a FLOAT with two digits after the dot.
From some reason, when I use the price in IF expression, the result is the same float with many additional digits:
mysql> select price, IF(1, price,0) as my_price from tbl_prices limit 10;
+-------+------------------+
| price | my_price |
+-------+------------------+
| 79.95 | 79.9499969482422 |
| 99.95 | 99.9499969482422 |
| 89.95 | 89.9499969482422 |
| 89.95 | 89.9499969482422 |
| 79.95 | 79.9499969482422 |
| 89.95 | 89.9499969482422 |
| 89.95 | 89.9499969482422 |
| 79.95 | 79.9499969482422 |
| 79.95 | 79.9499969482422 |
| 69.95 | 69.9499969482422 |
+-------+------------------+
10 rows in set (0.00 sec)
As you can see, price looks good, however the result of IF expression that returns the same price contains garbage.
Does anybody know what is the reason for this garbage, and how can I get rid of it (without using ROUND)?
Thanks in advance!
Just don't. A float is not an exact value. Use DECIMAL fields for example for a price.
Because you can't represent the .95 in floating point. This is the closest you will get. This is why float is approximate.
If you want exact decimal places, use DECIMAL
At first you should know how the floating point works.
Fortunately mysql provides DECIMAL data type, which can specify exact precision, for example:
DECIMAL( 10, 2)
Will store 10 decimal places long number and 2 digits out of that on right side, for example:
12345678.12
1.03
and so on.