How would I create a table that contains a geography point (lat/long) using PostGIS? Then also, what would the format be for inserting into this table (Using SQL/PostgreSQL)?
Would it just the following for table creation:
CREATE TABLE x (geog geography(point, 4326))
If so, what is the point and when would you instead use ST_Point(X,Y)
Should this column have an index?
Note: Many questions previously answered detail how to convert. But I want to create an empty table from scratch that supports storing latitude and longitude.
Yes, the Syntax for Creating a table with Geography is as simple as CREATE TABLE x (geog geography(POINT,4326) );
In this Command, POINT is the type of shape that this table will be storing. Other possibilities are :
LINESTRING
POLYGON
MULTIPOINT
MULTILINESTRING
MULTIPOLYGON
GEOMETRYCOLLECTION
The reason why storing a Geography in a table makes sense in some cases, is that it gives you the ability to run several functions which would give you results as if you are calculating on a Spherical Earth. So for example I could have two points stored as Geography (knowing only lat-long of each), and I could easily find the distance between them in Meters
ST_Point(X,Y) is just a function that takes in two numbers, and then creates a point which has X as the first number and Y as the second number. It need not be a Lat-long pair. Infact this Point has not concept of which Coordinate reference system it is in.
Once you create the table, inserting records in it, is as simple as:
INSERT INTO X (geog) VALUES (ST_GeographyFromText('POINT(2.5559 49.0083)'));
Here You are are creating a Geography point for Paris, with latitude of 49.0083N and longitude of 2.5559 E
Related
I have researched this for two days now and cannot find anything that works for me, it may be my database design, but I think it's designed ok.
I have a table called "post_codes_new", it contains the following columns;
id (int)
post_code (varchar, example: "0612")
post_code_name (varchar, example: "Henderson")
latlongs (geography data type - forming a polygon)
What I am attempting to do is query this table using a lat/long point to return any post_codes record that contains that lat/long (any record that the lat/long falls within the boundaries of).
Here's what I've been working on;
DECLARE #point geography;
SET #point = geography::STGeomFromText('POINT(174.94280000 -36.75000000)',4326)
select post_code
from dbo.post_codes_new
WHERE latlongs.MakeValid().STContains(#point) = 1;
No matter what lat/long point I enter here, my query returns me 931 of the 1081 records in that table and it takes 22 seconds.... It should only return one record. And I'm hoping for way better performance of course.
I'm trying to achieve this;
['PSEUDO-CODE' QUERY OF WHAT I'D LIKE TO ACHIEVE]
SELECT post_codes.* FROM post_codes WHERE latlongs.STIntersects(myLatLongPoint) = 1
The examples I have looked at (on this site and elsewhere) all seem to work with polygons that are defined within the query (ie, the points are listed in the query body explicitly). I have seen a few that look at records containing polygon boundaries, but none have worked for me.
Thanks.
Huge thanks to #BenThul and #TomC. It turned out that indeed, my points had been entered in a clockwise direction, which wraps the "rest of the world excluding your polygon" and creates that as a polygon area - hence the 931 out of 1081 records being returned in my query.
So I took my existing polygon points (that I had stored as a nvarchar(MAX) string, alongside my geography column) and reversed them, then over-wrote my geography column with those reversed values. I then ran the queries on a few known address/postcode combinations and it worked perfectly. A single postcode was returned per query, as expected. Brilliant!
It takes (consistently) 16 seconds for the query to run, but I'll work on that speed problem as a separate issue.
Thank you guys.
So I added geometry columns to a spatial table and using some of the msdn references I ended up specifying the SRID as 0 like so:
update dbo.[geopoint] set GeomPoint = geometry::Point([Longitude], [Latitude], 0)
However, I believe this was a mistake, but before having to update the column, is 0 actually the default = 4326? The query works as long as I specify the SRID as 0 on the query, but I'm getting weird results in comparison to the geography field I have... SRID 0 does not exist in sys.spatial_reference_systems and I haven't been able to dig up any information on it. Any help would be appreciated.
A SRID of 0 doesn't technically exist, it just means no SRID -- ie, the default if you forget to set it. So, technically, you can still perform distance, intersection and all other queries, so long as both sets of geometries have a SRID of 0. If you have one field of geometries with a SRID of 0 and another set with a SRID that actually exists, you will most likely get very strange results. I remember scratching my head once when not getting any results from a spatial query in exactly this situation and SQL Server did not complain, just 0 results (for what is is worth Postgis will actually fail, with a warning about non-matching SRIDs).
In my opinion, you should always explicitly set the SRID of your geometries (or geographies, which naturally will always be 4326), as not only does it prevent strange query results, but it means you can convert from one coordinate system to another. Being able to convert on the fly from lat/lon (4326), to Spherical Mercator (3857), as used in Google Maps/Bing, which is in meters, or some local coordinate system, such as 27700, British National Grid, also in meters, can be very useful. SQL Server does not to my knowledge support conversion from one SRID to another, but as spatial types are essentially CLR types, there are .NET libraries available should you ever need to do so, see Transform/ Project a geometry from one SRID to another for an example.
If you do decide to change you geometries, you can do something like:
UPDATE your_table SET newGeom = geometry::STGeomFromWKB(oldGeom.STAsBinary(), SRID);
which will create a new column or to do it in place:
UPDATE geom SET geom.STSrid=4326;
where 4326 is just an example SRID.
There is a good reference for SRIDs at http://spatialreference.org/, though this is essentially the same information as you find in sys.spatial_reference_systems.
SRIDs are a way to take into account that the distances that you're measuring on aren't on a flat, infinite plane but rather an oblong spheroid. They make sense for the geography data type, but not for geometry. So, if you're doing geographic calculations (as your statement of "in comparison to the geography field I have"), create geography points instead of geometry points. In order to do calculations on any geospatial data (like "find the distance from this point to this other point"), the SRID of all the objects involved need to be the same.
TL;DR: Is the point on the Cartesian plane? Use geometry. Is the point on the globe? Use geography.
I'm working with postgresql with postgis.
I have few questions:
trying to insert into a table with polygon column using the following syntax:
ST_GeomFromText('POLYGON((long1 lat1, long2 lat2, long3 lat3))')
fails with the following error: function geomfromtext(unknown) does not exist
what is the difference between
CREATE TABLE my_table (my_polys polygon);
and
CREATE TABLE my_table2 (my_polys GEOGRAPHY(POLYGON));
and why does the following:
INSERT INTO my_table (my_polys) VALUES ('
(51.504824, -0.125918),
(51.504930, -0.122743),
(51.504930, -0.110297),
(51.504824, -0.102229),
(51.503435, -0.099311)'
);
work fine with my_table and not with my_table2 (I've changed the table name to my_table2)
what is the maximum number of points a polygon can have?
The geography data type is mostly useful when your geometry might wrap around the date line. If it does not, you are better off using normal geometry data types, as most functions in Postgis are designed to work on planar geometries. If your data are lat/lon, you can explicitly set this when you create your column with:
create table foo geom geometry(POLYGON, 4326);
Explicitly setting the coordinate reference system is useful if you want to convert between one coordinate system and another and helps prevent suprises if you attempt to run an intersection, say, between geometries in different coordinate systems.
It is hard to imagine your insert fragment above working with any table, not only is there a trailing comma, but there is no st_geomfromtext, st_makepolygon or anything else to convert what you have written into any geometry.
I have no idea what the maximum size for a polygon is, although, as Chris has already said, you are likely to have performance issues with polygons of 1gb in size, when you try and do spatial queries on them.
Your polygon size is limited by the max storage size. I believe this is limited to 1gb for a toasted column, though my guess is that you are likely to run into performance issues long before you exceed the maximum number of points.
Polygon is a built in type in PostgreSQL, and PostGIS offers additional types for geometry and geography. As I understand it the built-in-types only work for 2d Euclidean space, while PostGIS offers additional options there.
As for why your query fails, I wonder which version of PostGIS you are running and why st_geomfromtext is calling geomfromtext.
I have a database, which uses the GGRS87 reference system, and contains x-y coordinates of objects. I need to convert them to lat/lon, so that I can store them in SQL Server 2012 using Geography data type.
Or is there a way I can use those x-y coordinates directly to create a geography data? Please let me know.
You can use the xy value directly to create the geometry objects, as long as you know the SRID code for the GGRS87 co-ordinate system (I think it's 4121).
Then use the STGeomFromText method to create your features. E.g.
INSERT INTO SpatialTable (GeogCol1)
VALUES (geography::STGeomFromText('POINT(122 47)', 4121));
I have a table where each row is part of a New Zealand map. What I really want to know is is a point within the map (ie the country data) or is it in the water.
I understand how StIntersects works but all examples are for a single Polygon or LineString but I have a table of LineStrings - 130 rows that define the country border.
Lots of rows like this
LINESTRING (6252032.7308424888 -3161950.9615992079, 6252033.7275789445 -3161929.3581238855, 6252011.5227283547 -3161906.1086780191, 6251992.0438580718 -3161880.6299652755)
So I think I need to sort of put all the line strings together to make my country border a single polygon or something like that, but I do not know how to do that.
Can someone give me an example of how I could do this?
The original data was from a ShapeFile from www.koordinates.com called New Zealand Coastlines. I then used Shape2Sql to import to SQL Server using Planer Geometry.
Geometry (spheric) in Shape2File said "Data projects or extent is outside the bounds of what is supported by the SqlGeography type)
Hope I have provided enough information?
Cheers Chris
You have most likely moved on from this but I am posting for future use.
If I understand you correctly, you need to create one polygon from a table of LINESTRINGs that make up the boundary of the polygon?
First, combine all of the LINESTRINGs in your table into one geometry like this:
DECLARE #g geometry
SELECT TOP 1 #g = geom from #geom_tmp
SELECT
#g = #g.STUnion(geom)
FROM
#geom_tmp
SELECT #g
Then you want to create a polygon from your single-line boundary. There are only two things that differ between your single-line boundary string and a polygon, first we replace "LINESTRING" with "POLYGON". Then we add a set of parentheses since a polygon's WKT string separates multiple polygons with parentheses like this:
DECLARE #str NVARCHAR(max)
SET #str = REPLACE(REPLACE(#g.STAsText(),'(','((') + ')','LINESTRING','POLYGON')
SET #g = GEOMETRY::STGeomFromText(#str,0)
SELECT #g
Which will give you your polygon of the country.
Then you simply see if your point intersects the polygon (#p is the point geometry):
SELECT #p.STIntersects(#g)
-- OUTPUT is 1 if it intersects and 0 if it does not.
OR if your points are in a table, you could select the list of points that intersect the country as shown below if the point table geometry column is called "point".
SELECT *
FROM point_table
WHERE point.STIntersects(#g) = 1
Since there are many of us who cannot move to SQL server 2012 any time soon, this comes in handy. Hope it helps.
The classic approach to determine whether two points are on the same side (inside or outside) of a polygon, is to calculate the number of intersections between a line connecting the two and borders of the polygon. Even number (incl. 0) is same side, odd is different sides.
So define one (any) point which is inside New Zealand for sure (preferably near geometric middle), then a line that connects it with the point you want to check, then calculate the number of lines it intersects. If it's 0 or even, the other point is on the same side (that is in New Zealand.) If it's odd, the point is outside the country borders. You don't need to worry about ordering or connecting the border lines.
It becomes more tricky if the line crosses exactly through a joint point between two border lines, but StIntersects won't save you against that, and besides if you work on real values with 17 significant places, the likehood for this to occur is minimal.
The algorithm is good here in that it works for multiple disjoint polygons (isles) just as well as for single irregular polygon. The only requirement is all the lines are closed.
Of course to get that to work you'd have to transform linestrings into a set of single lines and store these, because you need to find number of intersections, not just fact: line intersects polygon (n times) vs 0 times.
Let me see if I understand your problem.
You wish to determine if a pre-determined point is either INSIDE NZ or OUTSIDE. Now, you have the coastline of NZ, right? This coastline is around 130 rows ... but we need to make this one single row .. and THEN see if the point lies inside this boundary or outside.
If this is correct, then the first thing you'll need to do is to join all the linestrings into a single massive polygon .. and we need this final single row as a Sql Server 2008 GEOGRAPHY type.
So - first some help. Jump over to Codeplex and grab this library - sql spatial tools. In this library, there is a method to JOIN all the linestrings. I think it's called GeographyUnionAggregate . Figure out how to run this stored proc which will join all the linestrings together (assuming none of them are messed up).
Once this task is done, you will have a single GEOGRAPHY row which repesents the entire coastline of NZ.
Now, it's a simple sql statement to see if the point exists/intersects the boundary (the country of NZ) or not :-
DECLARE #SomePoint GEOGRAPHY
SET #SomePoint = geography::STGeomFromText('POINT(-122.358 47.653)', 4326);
SELECT CountryId, Name
FROM Countries a
INNER JOIN a.AdministrativeBoundary.STIntersects(#SomePoint) = 1
And that should return you one result :)