What MySQL data type should be used for Latitude/Longitude with 8 decimal places?
MysqlTypesFloating PointMysql Problem Overview
I'm working with map data, and the Latitude/Longitude
extends to 8 decimal places. For example:
Latitude 40.71727401
Longitude -74.00898606
I saw in the [Google document][1] which uses:
lat FLOAT( 10, 6 ) NOT NULL,
lng FLOAT( 10, 6 ) NOT NULL
however, their decimal places only go to 6.
Should I use FLOAT(10, 8)
or is there another method to consider for storing this data so it's precise. It will be used with map calculations. Thanks!
[1]: https://developers.google.com/maps/articles/phpsqlsearch_v3#createtable "Google Document"
Mysql Solutions
Solution 1 - Mysql
MySQL supports Spatial data types and Point
is a single-value type which can be used. Example:
CREATE TABLE `buildings` (
`coordinate` POINT NOT NULL,
/* Even from v5.7.5 you can define an index for it */
SPATIAL INDEX `SPATIAL` (`coordinate`)
) ENGINE=InnoDB;
/* then for insertion you can */
INSERT INTO `buildings`
(`coordinate`)
VALUES
(POINT(40.71727401 -74.00898606));
Solution 2 - Mysql
in laravel used decimal column type for migration
$table->decimal('latitude', 10, 8);
$table->decimal('longitude', 11, 8);
for more information see available column type
Solution 3 - Mysql
Additionally, you will see that float
values are rounded.
// e.g: given values 41.0473112,29.0077011float(11,7) | decimal(11,7)
41.0473099 | 41.0473112 29.0077019 | 29.0077011
Solution 4 - Mysql
Do not use float... It will round your coordinates, resulting in some strange occurrences.
Use decimal
Solution 5 - Mysql
I believe the best way to store Lat/Lng in MySQL is to have a POINT column (2D datatype) with a SPATIAL index.
CREATE TABLE `cities` (
`zip` varchar(8) NOT NULL,
`country` varchar (2) GENERATED ALWAYS AS (SUBSTRING(`zip`, 1, 2)) STORED,
`city` varchar(30) NOT NULL,
`centre` point NOT NULL,
PRIMARY KEY (`zip`),
KEY `country` (`country`),
KEY `city` (`city`),
SPATIAL KEY `centre` (`centre`)
) ENGINE=InnoDB;
INSERT INTO `cities` (`zip`, `city`, `centre`) VALUES
('CZ-10000', 'Prague', POINT(50.0755381, 14.4378005));
Solution 6 - Mysql
MySQL now has support for spatial data types since this question was asked. So the the current accepted answer is not wrong, but if you're looking for additional functionality like finding all points within a given polygon then use POINT data type.
Checkout the Mysql Docs on Geospatial data types and the spatial analysis functions
Solution 7 - Mysql
You can set your data-type as signed integer. When you storage coordinates to SQL you can set as lat10000000 and long10000000. And when you selecting with distance/radius you will divide storage coordinates to 10000000. I was test it with 300K rows, query response time is good. ( 2 x 2.67GHz CPU, 2 GB RAM, MySQL 5.5.49 )
Solution 8 - Mysql
Accuracy of 6 decimal places is about 16cm, which means 2 object have the same lat and lng if they are less than 16cm far from each other.
Also, in mariadb/mysql, using float/double is not ideal if we have huge data for indexing, and Point datatype is overhead for data size. It'd better to use decimal or convert lat long to INT.
It's good option to use decimal with 6 decimal places as we can ignore convert, and we have only 16cm inaccuracy, longitude is between -180 to 180, thus require 1 digit more than latitude, which is between -90 to 90 degree:
Lat DECIMAL(8,6)
Lng DECIMAL(9,6)
We can extend to 8 decimal places:
Lat DECIMAL(10,8)
Lng DECIMAL(11,8)
Solution 9 - Mysql
CREATE TABLE your_table_name (
lattitude REAL,
longitude REAL
)
also consider adding further verifications to your lat, long declaration:
CREATE TABLE your_table_name (
lattitude REAL CHECK(lattitude IS NULL OR (lattitude >= -90 AND lattitude <= 90)),
longitude REAL CHECK(longitude IS NULL OR (longitude >= -180 AND longitude <= 180))
)
explanation : https://dev.mysql.com/doc/refman/5.7/en/floating-point-types.html
Solution 10 - Mysql
Using migrate ruby on rails
class CreateNeighborhoods < ActiveRecord::Migration[5.0]
def change
create_table :neighborhoods do |t|
t.string :name
t.decimal :latitude, precision: 15, scale: 13
t.decimal :longitude, precision: 15, scale: 13
t.references :country, foreign_key: true
t.references :state, foreign_key: true
t.references :city, foreign_key: true
t.timestamps
end
end
end
Solution 11 - Mysql
You should simply use varchar (20)