Location data are information about the geographic positions of devices (such as smartphones or tablets) or structures (such as buildings, attractions). The geographic positions of location data are called coordinates, and they are commonly expressed in Latitude and Longitude format.
Continuous numerical data take any value within an allowable range, whereby the range can be finite or infinite. Even though Latitudes are in a finite range, they can have any value, with any level of specificity (or decimal places). So, latitudes, should be Continuous Numerical data.
There are two basic types of location data: vector data and raster data.
The latitude and longitude are displayed in decimal notation. The number of decimal places must be specified and between 1 and 6 inclusive. -dd dd'dd" - Degrees, minutes, and seconds. The latitude and longitude are displayed as integers in degrees, followed by minutes and seconds.
You can use the data type point
- combines (x,y)
which can be your lat / long. Occupies 16 bytes: 2 float8
numbers internally.
Or make it two columns of type float
(= float8
or double precision
). 8 bytes each.
Or real
(= float4
) if additional precision is not needed. 4 bytes each.
Or even numeric
if you need absolute precision. 2 bytes for each group of 4 digits, plus 3 - 8 bytes overhead.
Read the fine manual about numeric types and geometric types.
The geometry
and geography
data types are provided by the additional module PostGIS and occupy one column in your table. Each occupies 32 bytes for a point. There is some additional overhead like an SRID in there. These types store (long/lat), not (lat/long).
Start reading the PostGIS manual here.
In PostGIS, for points with latitude and longitude there is geography datatype.
To add a column:
alter table your_table add column geog geography;
To insert data:
insert into your_table (geog) values ('SRID=4326;POINT(longitude latitude)');
4326 is Spatial Reference ID that says it's data in degrees longitude and latitude, same as in GPS. More about it: http://epsg.io/4326
Order is Longitude, Latitude - so if you plot it as the map, it is (x, y).
To find closest point you need first to create spatial index:
create index on your_table using gist (geog);
and then request, say, 5 closest to a given point:
select *
from your_table
order by geog <-> 'SRID=4326;POINT(lon lat)'
limit 5;
I strongly advocate for PostGis. It's specific for that kind of datatype and it has out of the box methods to calculate distance between points, among other GIS operations that you can find useful in the future
If you do not need all the functionality PostGIS offers, Postgres (nowadays) offers an extension module called earthdistance. It uses the point or cube data type depending on your accuracy needs for distance calculations.
You can now use the earth_box function to -for example- query for points within a certain distance of a location.
In PostGIS Geometry is preferred over Geography (round earth model) because the computations are much simpler therefore faster. It also has MANY more available functions but is less accurate over very long distances.
Import your CSV long and lat fields to DECIMAL(10,6)
columns. 6 digits is 10cm precision, should be plenty for most use cases. Then cast your imported data to the correct SRID
The wrong way!
/* try what seems the obvious solution */
DROP TABLE IF EXISTS public.test_geom_bad;
-- Big Ben, London
SELECT ST_SetSRID(ST_MakePoint(-0.116773, 51.510357),4326) AS geom
INTO public.test_geom_bad;
The CORRECT way
/* add the necessary CAST to make it work */
DROP TABLE IF EXISTS public.test_geom_correct;
SELECT ST_SetSRID(ST_MakePoint(-0.116773, 51.510357),4326)::geometry(Geometry, 4326) AS geom
INTO public.test_geom_correct;
Verify SRID is not zero!
/* now observe the incorrect SRID 0 */
SELECT * FROM public.geometry_columns
WHERE f_table_name IN ('test_geom_bad','test_geom_correct');
Validate the order of your long lat parameter using a WKT viewer and
SELECT ST_AsEWKT(geom) FROM public.test_geom_correct
Then index it for best performance
CREATE INDEX idx_target_table_geom_gist
ON target_table USING gist(geom);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With