399

When storing latitude or longitude data in an ANSI SQL compliant database, what datatype would be most appropriate? Should float be used, or decimal, or ...?

I'm aware that Oracle, MySql, and SQL Server have added some special datatypes specifically for handling geo data, but I'm interested in how you would store the information in a "plain vanilla" SQL database.

j0k
  • 22,600
  • 28
  • 79
  • 90
dthrasher
  • 40,656
  • 34
  • 113
  • 139
  • 5
    Atul is right, it isn't the same question also because the other one specifies that calculations will be made on lat/lng. I just realized that my answer from the other one is best suited here, so please have a look: http://stackoverflow.com/a/25120203/1226018 – Simon Oct 01 '15 at 17:18

8 Answers8

604

For latitudes use: Decimal(8,6), and longitudes use: Decimal(9,6)

If you're not used to precision and scale parameters, here's a format string visual:

Latitude and Longitude ##.###### and ###.######

To 6 decimal places should get you to around ~10cm of accuracy on a coordinate.

Community
  • 1
  • 1
dotjoe
  • 26,242
  • 5
  • 63
  • 77
  • 37
    +1: Avoid round-off error weirdness by using a fixed number of decimal places. – S.Lott Jul 28 '09 at 20:09
  • 14
    For their purposes Wikipedia suggests: "Avoid excessive precision (0.0001° is <11 m, 1′′ is <31 m)." http://en.wikipedia.org/wiki/Wikipedia:Obtaining_geographic_coordinates To make my fields extra precise, I've also decided to use six digits right of the decimal mark, and three on the left. I'm glad this answer confirms it was a good decision. – Dragoljub Ćurčić Feb 17 '10 at 12:16
  • 1
    Check the last answer but one in this [article](http://groups.google.com/group/google-maps-api/browse_thread/thread/b928b5fbc5351821). The user William explains very well what happen with precision while you get far from the equator. – Throoze Apr 15 '12 at 09:32
  • 14
    Also, if you are not going to operate with the numbers, consider storing them as a string. Using `varchar(20)` would be extra precise, and also cheap in storage space. – Throoze Apr 15 '12 at 09:34
  • That's funny, was just checking that I used a good value DECIMAL(9,6) in the DB, but it's interfacing via NodeJS (which xfers as a float value tot he db anyway) so wanted to double-check. – Tracker1 Dec 12 '12 at 21:16
  • 82
    (8,6) for latitudes and (9,6) for longitudes – Neil McGuigan Sep 27 '13 at 19:36
  • 4
    why latitude (8,6) and Longitudes (9.6)... ?, any reason ?, why not both (9.6) ? – makitocode Apr 10 '15 at 17:59
  • 18
    @Makito latititudes go from -90 to 90 degrees...so only need 2 places left of decimal point... – dotjoe Apr 10 '15 at 19:21
  • 2
    @Throoze Can you explain the reasoning behind suggesting `varchar(20)`? I won't be doing any operations, other than sending co-ordinates to Google Maps API, so am curious on the benefits of using `VARCHAR(20)` instead of `DECIMAL(9,6)`. Thank you! – Shiva Mar 26 '17 at 19:19
  • 2
    @Shiva well geolocation datatypes are useful only if you are going to operate with them with any GIS driver or app. But if you only intend to store them, a string is more than enough. Eitherways, if you need to do some fancy operations with the values stored, take a look at [this article](http://groups.google.com/group/google-maps-api/browse_thread/thread/b928b5fbc5351821) where they elaborate more on precision and using these values in a javascript app. It really is up to you I guess. Remember that Google maps API uses Json objects, so for them everything is a string. – Throoze Apr 05 '17 at 00:26
  • With regards to the suggestions to store as VARCHAR, doesn't it actually use more space than a precision 9 decimal? -176.824107 in DECIMAL(9,6) would take 5 bytes while as a VARCHAR it would take 11 bytes (in UTF-8). – DrewF Feb 01 '20 at 18:48
  • 1
    A very niche case but the Australian Beuro of Statistics provides accuracy to 8 decimal places, so I use Dec 11,8 – Shaedo Sep 05 '20 at 16:44
9

We use float, but any flavor of numeric with 6 decimal places should also work.

Keith
  • 5,311
  • 3
  • 34
  • 50
  • 41
    A calculation might introduce extra digits which would only be noise. Also the decimal-to-binary transformation will make the final decimal place suspicious and possibly wrong. Fine for some purposes. Lousy for navigation. – S.Lott Jul 28 '09 at 20:10
  • 1
    I don't think suggesting float deserves a down-rate - you made me second-guess and search elsewhere for an answer: http://stackoverflow.com/questions/551894/whats-the-best-way-to-store-co-ordinates-longitude-latitude-from-google-maps – Keith Jul 28 '09 at 21:36
  • The question is about storing. A 32-bit float is the most efficient way to store. If you need to do a lot of calculations, and can show that rounding errors matter, then cast to 64-bit float first. – nilskp Jul 02 '13 at 15:09
2

I would use a decimal with the proper precision for your data.

Sam
  • 7,543
  • 7
  • 48
  • 62
2

You should take a look at the new Spatial data-types that were introduced in SQL Server 2008. They are specifically designed this kind of task and make indexing and querying the data much easier and more efficient.

http://msdn.microsoft.com/en-us/library/bb933876(v=sql.105).aspx

T3.0
  • 446
  • 1
  • 6
  • 21
syed Ahsan Jaffri
  • 1,160
  • 2
  • 14
  • 34
2

You can easily store a lat/lon decimal number in an unsigned integer field, instead of splitting them up in a integer and decimal part and storing those separately as somewhat suggested here using the following conversion algorithm:

as a stored mysql function:

CREATE DEFINER=`r`@`l` FUNCTION `PositionSmallToFloat`(s INT) 
RETURNS decimal(10,7)
DETERMINISTIC
RETURN if( ((s > 0) && (s >> 31)) , (-(0x7FFFFFFF - 
(s & 0x7FFFFFFF))) / 600000, s / 600000)

and back

CREATE DEFINER=`r`@`l` FUNCTION `PositionFloatToSmall`(s DECIMAL(10,7)) 
RETURNS int(10)
DETERMINISTIC
RETURN s * 600000

That needs to be stored in an unsigned int(10), this works in mysql as well as in sqlite which is typeless.

through experience, I find that this works really fast, if all you need to to is store coordinates and retrieve those to do some math with.

in php those 2 functions look like

function LatitudeSmallToFloat($LatitudeSmall){
   if(($LatitudeSmall>0)&&($LatitudeSmall>>31)) 
     $LatitudeSmall=-(0x7FFFFFFF-($LatitudeSmall&0x7FFFFFFF))-1;
   return (float)$LatitudeSmall/(float)600000;
}

and back again:

function LatitudeFloatToSmall($LatitudeFloat){
   $Latitude=round((float)$LatitudeFloat*(float)600000);
   if($Latitude<0) $Latitude+=0xFFFFFFFF;
   return $Latitude;
}

This has some added advantage as well in term of creating for example memcached unique keys with integers. (ex: to cache a geocode result). Hope this adds value to the discussion.

Another application could be when you are without GIS extensions and simply want to keep a few million of those lat/lon pairs, you can use partitions on those fields in mysql to benefit from the fact they are integers:

Create Table: CREATE TABLE `Locations` (
  `lat` int(10) unsigned NOT NULL,
  `lon` int(10) unsigned NOT NULL,
  `location` text,
  PRIMARY KEY (`lat`,`lon`) USING BTREE,
  KEY `index_location` (`locationText`(30))
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*!50100 PARTITION BY KEY ()
PARTITIONS 100 */
Glenn Plas
  • 1,608
  • 15
  • 17
2

In vanilla Oracle, the feature called LOCATOR (a crippled version of Spatial) requires that the coordinate data be stored using the datatype of NUMBER (no precision). When you try to create Function Based Indexes to support spatial queries it'll gag otherwise.

1

I think it depends on the operations you'll be needing to do most frequently.

If you need the full value as a decimal number, then use decimal with appropriate precision and scale. Float is way beyond your needs, I believe.

If you'll be converting to/from degºmin'sec"fraction notation often, I'd consider storing each value as an integer type (smallint, tinyint, tinyint, smallint?).

jpj625
  • 1,138
  • 11
  • 6
1

Well, you asked how to store Latitude/Longitude and my answer is: Don't, you might consider using the WGS 84 ( in Europe ETRS 89 ) as it is the standard for Geo references.

But that detail aside I used a User Defined Type in the days before SQL 2008 finally include geo support.

Kasper
  • 1,710
  • 2
  • 17
  • 31
  • 2
    I am curious, can you remember what you meant when you suggested to not save the latitude and longitude? What were you thinking you would save instead? – Matt Kieran Apr 15 '18 at 15:04
  • 1
    I'm not sure what Kasper is saying here. Lat/Long is a position format (equivalent to UTM, MGRS, NZTM etc), whereas WGS84 is a datum - a reference system that position coordinates are applied to. You need to know *both* your coordinates and which datum you are using, although for online use it is almost always WGS84. – Mike Feb 12 '20 at 11:06
  • Yeah, this is a really unhelpful answer to say "don't" and then not elaborate on their reasoning. – Code Commander Jul 17 '23 at 19:53