I am learning postgis 2.1. I created a postgis table from a shapefile and imported it into the DB. It made a table like this:

db=# \d districts 
     geog       | geography(MultiPolygon,4326) | 

I also created a table "callsforservice" importing tabular data from a CSV, which I then converted into points with a SRID = 4326.

db=# update callsforservice set latlongpointdetails = ST_SetSRID(latlongpoint, 4326);

I want to know which callsforservice.latlongpointdetails are included in which districts.geogs

I tried with this query, which takes very, very, very long time. The limit 1 is only to shorten the time the query is running. After 2 min or so I kill it:

select * from callsforservice, districts where ST_Within(geometry(districts.geog), callsforservice.latlongpointdetails) limit 1; 

If I add an additional condition to the where clause (where districts.district='1-1') -- this query returns immediately with 0 rows, even though districts does have a row with this ID.

Do I have the syntax right for finding out which calls came in what districts?

The docs for ST_within say "the source geometries must both be of the same coordinate projection, having the same SRID." If I examine the two tables with the \dt command then the geog column in districts shows type geography(MultiPolygon,4326) but the latlongpointdetails column in callsforservices only shows type geometry -- without parenthesis like in the districts table. Maybe this is the reason for the failures of ST_Within? Where am I going wrong?

  • Did you have an index on the geometry column? You can add an index using something like this CREATE INDEX idx_districts ON geog USING GIST ( geog );
    – djq
    Mar 31, 2014 at 2:47
  • @djq that index helped a bunch. Also using the && operator, as suggested in the (old version of the) docs postgis.net/docs/manual-1.3/ch03.html Feel free to answer and I will accept
    – bernie2436
    Mar 31, 2014 at 3:15

2 Answers 2


You shouldn't be mixing geometry with geography in your query. If all you are going to do is convert your geography to geometry (which is what geometry(districts.geog) does), there isn't any point in having it as geography. What would make more sense is to change your callsforservice.latlongpointdetails to geography type since geography is more correct.

ALTER TABLE callsforservice
  ALTER COLUMN latlongpointdetails TYPE geography 
     USING latlongpointdetails::geography(POINT,4326);

CREATE INDEX idx_callsforservice_latlongpointdetails ON callsforservice USING GIST(latlongpointdetails);

You also want to make sure that your latlongpointdetails is in long,lat (not lat,long). You don't need && if you are comparing apples with apples. ST_Within has a && call built into it. Also I don't think ST_Within is supported for geography (well not listed, though surprise it doesn't), and your ST_Within (should be point within polygon not polygon within point) call looks backward to me so not sure how you are getting anything back. Use ST_Covers instead -- http://postgis.net/docs/manual-2.1/ST_Covers.html

select * from callsforservice 
  INNER JOIN districts 
      ON ST_Covers(districts.geog, callsforservice.latlongpointdetails) limit 1;

Do you have an index on the geometry column? You can add an index using something like this

CREATE INDEX idx_districts ON geog USING GIST ( geog );

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.