I have a table containing latitude and longitude values stored as strings (VARCHAR) which I'd like to convert to FLOAT (10,6).
However there doesn't appear to be a straightforward way to do this using CAST() or CONVERT().
How can I convert these columns easily? This is a one-time conversion.
It turns out I was just missing DECIMAL on the CAST() description:
DECIMAL[(M[,D])]
Converts a value to DECIMAL data type. The optional arguments M and D specify the precision (M specifies the total number of digits) and the scale (D specifies the number of digits after the decimal point) of the decimal value. The default precision is two digits after the decimal point.
Thus, the following query worked:
UPDATE table SET
latitude = CAST(old_latitude AS DECIMAL(10,6)),
longitude = CAST(old_longitude AS DECIMAL(10,6));
mysql> SELECT CAST(4 AS DECIMAL(4,3));
+-------------------------+
| CAST(4 AS DECIMAL(4,3)) |
+-------------------------+
| 4.000 |
+-------------------------+
1 row in set (0.00 sec)
mysql> SELECT CAST('4.5s' AS DECIMAL(4,3));
+------------------------------+
| CAST('4.5s' AS DECIMAL(4,3)) |
+------------------------------+
| 4.500 |
+------------------------------+
1 row in set (0.00 sec)
mysql> SELECT CAST('a4.5s' AS DECIMAL(4,3));
+-------------------------------+
| CAST('a4.5s' AS DECIMAL(4,3)) |
+-------------------------------+
| 0.000 |
+-------------------------------+
1 row in set, 1 warning (0.00 sec)
This will convert to a numeric value without the need to cast or specify length or digits:
STRING_COL+0.0
If your column is an INT, can leave off the .0 to avoid decimals:
STRING_COL+0
Related
I am trying to do IPv6 address range matching using LineString and Point. But I believe this question is more related to how MySQL handles large number precision in general. (Note the following works without issues with smaller numbers, i.e. IPv4 decimal representation).
For IPv4, the ranges are defined as LineString(Point(-1, ip_start), Point(1, ip_end)).
I seem to be losing precision when creating a Point() with a large number, therefore my range matching is flawed.
MariaDB [mydb]> set #point=Point(0, 42541828702485584113142439188939931648);
Query OK, 0 rows affected (0.00 sec)
MariaDB [mydb]> select astext(#point);
+-------------------------------+
| astext(#point) |
+-------------------------------+
| POINT(0 4.254182870248558e37) |
+-------------------------------+
1 row in set (0.00 sec)
MariaDB [mydb]> select st_y(#point);
+----------------------+
| st_y(#point) |
+----------------------+
| 4.254182870248558e37 |
+----------------------+
1 row in set (0.00 sec)
MariaDB [mydb]> select cast(st_y(#point) as Decimal(39));
+----------------------------------------+
| cast(st_y(#point) as Decimal(39)) |
+----------------------------------------+
| 42541828702485580000000000000000000000 |
+----------------------------------------+
1 row in set (0.00 sec)
MariaDB [mydb]>
How can I use a Point() with large numbers accurately?
SPATIAL functions (st_x, point, etc) work with DOUBLEs, not DECIMAL.
DECIMAL(39) should work. But why not just keep it as a string or hex string (VARCHAR(39) CHARACTER SET ascii) or BINARY(16)?
Please explain your ultimate goal that led you to want to use Spatial tools.
Here is code to handle ranges of IP addresses (separate code for IPv4 or IPv6): http://mysql.rjweb.org/doc.php/ipranges
I have a table in mysql with a field type float(10, 7).
I am trying to insert value 1196.104, Even when using phpmyadmin it converts that value to 1000.0000000.
What type should I use to properly store the value 1196.104 in database.
This is working exactly as intended by the FLOAT(10,7). When you give a value that won't fit in the number of digits, it caps the value and uses the greatest value that can fit.
In this case, the 10-digit value of 999.9999999, rounded up to 1000.0000000.
https://dev.mysql.com/doc/refman/8.0/en/floating-point-types.html says:
MySQL permits a nonstandard syntax: FLOAT(M,D) or REAL(M,D) or DOUBLE PRECISION(M,D). Here, (M,D) means than values can be stored with up to M digits in total, of which D digits may be after the decimal point.
In other words, you gave it the constraint to max out at 1000.0000000, because you told it to max out at 10 digits, of which 7 digits are to the right of the decimal point.
mysql> create table f ( f float(10,7));
mysql> insert into f values (1196.104);
Query OK, 1 row affected, 1 warning (0.02 sec)
mysql> show warnings;
+---------+------+--------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------+
| Warning | 1264 | Out of range value for column 'f' at row 1 |
+---------+------+--------------------------------------------+
mysql> select * from f;
+--------------+
| f |
+--------------+
| 1000.0000000 |
+--------------+
If you want to store larger values, declare FLOAT with enough digits to hold the values you use. For example, the value 1196.104 could be inserted to FLOAT(11,7) or FLOAT(10,6).
Or you could use FLOAT with no arguments, and it will not constrain the number of digits at all.
There are some caveats about FLOAT. It's an inexact numeric type, and it will have rounding errors. This is unavoidable because of the way FLOAT is implemented, and it affects every programming language.
Read https://dev.mysql.com/doc/refman/8.0/en/problems-with-float.html and https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Also see my old tweet about this:
https://twitter.com/billkarwin/status/347561901460447232
I was trying to feed a result of a query as a parameter for another query and all was working fine except this field that has a datatype of bit. so i tried to convert the value of the field using convert() and cast() but it seems to be not working as its returning this wierd symbol of a small rectange which hava three 0's and a 1. so can anyone tell me why this is happening and how to fix it , here is my query
select CONVERT(isMale , char(5)) from person;
and the thing is it gives me the correct answer when i dont use the convert but since am giving this result to another query as a parameter it causing me the problem.
you can use BIN function like this:
SELECT BIN(isMale +0) from person;
sample
MariaDB [yourschema]> SELECT BIN(b'1001' +0) ;
+-----------------+
| BIN(b'1001' +0) |
+-----------------+
| 1001 |
+-----------------+
1 row in set (0.00 sec)
MariaDB [yourschema]>
Here some stuff from MariaDB Manual:
Description
Converts numbers between different number bases. Returns a
string representation of the number N, converted from base from_base
to base to_base.
Returns NULL if any argument is NULL, or if the second or third
argument are not in the allowed range.
The argument N is interpreted as an integer, but may be specified as
an integer or a string. The minimum base is 2 and the maximum base is
36. If to_base is a negative number, N is regarded as a signed number. Otherwise, N is treated as unsigned. CONV() works with 64-bit
precision.
Some shortcuts for this function are also available: BIN(), OCT(),
HEX(), UNHEX(). Also, MariaDB allows binary literal values and
hexadecimal literal values.
BIN is a short form from CONV(value,from,to) where you can convert from base to base
so binary 1001 = 9 as int
here i give the value in decimal (14) and convert it from base 10 to base 2
MariaDB [yourschema]> SELECT CONV(14,10 ,2);
+-----------------+
| CONV(14,10 ,2) |
+-----------------+
| 1110 |
+-----------------+
1 row in set (0.00 sec)
so, if you want to have 0 on the left you can add a value like this
MariaDB [yourschema]> SELECT CONV(8192 + 14,10 ,2);
+------------------------+
| CONV(8192 + 14,10 ,2) |
+------------------------+
| 10000000001110 |
+------------------------+
1 row in set (0.00 sec)
and then you can get n chars from right:
MariaDB [yourschema]> SELECT RIGHT(CONV(8192 + 14,10 ,2),8);
+---------------------------------+
| RIGHT(CONV(8192 + 14,10 ,2),8) |
+---------------------------------+
| 00001110 |
+---------------------------------+
1 row in set (0.40 sec)
MariaDB [yourschema]>
I think you want to use CAST
select CAST(isMale as CHAR) from person;
seeing #Bernd Buffen answer i tried using the convert with +0 and it works , eventhough i dont know why
select CONVERT(isMale +0, char(5)) from person;
I am not clear how the mathematical operations are done in SQL.
For example in Java the numbers are "extended" to integers before applying an operation and when the other operand is of higher type or diffent precision we get conversions. Same in C++.
But what happens in SQL? Is there a default type that they are "extended" regardless if the underlying data type and we get same kind of conversions?
Update:
I also have the following example:
mysql> select sum from float_test;
+-------+
| sum |
+-------+
| 59.95 |
+-------+
1 row in set (0.00 sec)
mysql> select sum*(0.2) from float_test;
+--------------------+
| sum*(0.2) |
+--------------------+
| 11.990000152587891 |
+--------------------+
1 row in set (0.00 sec)
sum is a float so it is displayed with 2 digit precision but it is stored differently (due to rounding errors inherent in floats etc).
When I multiply with 0.2 I get this number.
I understand that it is due to using a float but why does it show so many digits and not just 2 i.e. 11.99 like the first SELECT that shows 59.95 (although 59.95000002322 something is stored)?
I have seen some programmers using this condition 0='"="1' and don't know why it returns true ?Can anyone explain it to me ? Thank you!
In order to compare an number with a string the string is cast to a number.
When casting a string to a number, mysql accepts all leading numbers and throws away the rest. When there are no leading numbers, the string is cast to zero:
0 = 'abc' -- true: string cast to 0
1 = '1abc' -- true: string cast to 1
Your string is evaluated as being 0 because there are no leading numbers.
The issue has no relation with "unusual" looks of the string. Yes. it's just primitive implicit type-conversion. You can do:
mysql> select 0='blablabla';
+---------------+
| 0='blablabla' |
+---------------+
| 1 |
+---------------+
1 row in set, 1 warning (0.00 sec)
And see your reason:
mysql> show warnings;
+---------+------+-----------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'blablabla' |
+---------+------+-----------------------------------------------+
1 row in set (0.00 sec)
So same with your '"="1' - it's just string and will be truncated during conversion to DOUBLE causing zero-value.