└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # Postgis Geo Cookbook 2 | 3 | A collection of snippets and best practices for using PostGIS. 4 | 5 | ## Select 6 | 7 | Select feature that does not exists in database 8 | ```sql 9 | SELECT location 10 | FROM kingston 11 | WHERE NOT EXISTS ( 12 | SELECT location 13 | FROM geocoder 14 | WHERE kingston.location = geocoder.location AND 15 | geocoder.provider = 'Bing') 16 | ``` 17 | 18 | Cross Join 19 | ```sql 20 | SELECT count(*) 21 | FROM kingston as p1 22 | CROSS JOIN (SELECT provider FROM geocoder GROUP by provider) AS p2 23 | ``` 24 | 25 | Remove Duplicate 26 | ```sql 27 | DELETE FROM tablename 28 | WHERE id IN (SELECT id 29 | FROM (SELECT id, 30 | row_number() over (partition BY column1, column2, column3 ORDER BY id) AS rnum 31 | FROM tablename) t 32 | WHERE t.rnum > 1); 33 | ``` 34 | 35 | 36 | Make a line from two points 37 | ```sql 38 | DELETE FROM lines; 39 | 40 | INSERT INTO lines (provider, location, address, geom, distance) 41 | SELECT p1.provider, p2.location, p1.address, ST_MakeLine(ST_Union(p1.geom),ST_Centroid(ST_Union(p2.geom))), ST_Length(ST_MakeLine(ST_Union(p1.geom),ST_Centroid(ST_Union(p2.geom))), True) 42 | FROM geocoder as p1 43 | LEFT JOIN kingston as p2 44 | ON p1.location = p2.location 45 | GROUP BY p1.provider, p2.location, p1.address 46 | ``` 47 | 48 | Copy a select to CSV document 49 | ```sql 50 | COPY ( 51 | 52 | SELECT line.address as address, line.location as location, ST_X(kingston.geom) as x, ST_Y(kingston.geom) as y, line.distance as distance 53 | FROM line 54 | LEFT JOIN kingston 55 | ON line.location = kingston.location 56 | WHERE provider = 'OSM' and distance > 200 57 | 58 | ) to 'C:/tmp/Kingston Geocoding - OSM Errors 200m.csv' WITH CSV HEADER 59 | ``` 60 | 61 | Copy a selection which does not exists to CSV document 62 | ```sql 63 | COPY ( 64 | 65 | SELECT location, ST_X(kingston.geom) as x, ST_Y(kingston.geom) as y 66 | FROM kingston 67 | WHERE NOT EXISTS ( 68 | SELECT location 69 | FROM geocoder 70 | WHERE kingston.location = geocoder.location AND 71 | geocoder.provider = 'MapQuest') 72 | 73 | ) to 'C:/tmp/Kingston Geocoding - MapQuest Errors NOT FOUND.csv' WITH CSV HEADER 74 | ``` 75 | 76 | Copy a selection with a distance greater than 200m 77 | ```sql 78 | COPY ( 79 | 80 | SELECT line.address as address, line.location as location, ST_X(kingston.geom) as x, ST_Y(kingston.geom) as y, line.distance as distance 81 | FROM line 82 | LEFT JOIN kingston 83 | ON line.location = kingston.location 84 | WHERE provider = 'Google' and distance > 200 85 | 86 | ) to 'C:/tmp/Kingston Geocoding - Google Errors 200m.csv' WITH CSV HEADER 87 | ``` 88 | 89 | Select the postal code from a single point 90 | ```sql 91 | select kingston.location, postal.fsa 92 | from kingston, postal 93 | WHERE ST_Contains(postal.geom, kingston.geom) 94 | ``` 95 | 96 | Select the greatest distance between multiple points 97 | ```sql 98 | SELECT p1.provider, p1.name, SUM(ST_Distance(p1.geom, p2.geom, true)) as distance 99 | FROM location as p1 100 | LEFT JOIN location as p2 101 | ON p1.name = p2.name and p1.provider <> p2.provider 102 | GROUP BY p1.provider, p1.name 103 | ORDER BY distance 104 | ``` 105 | 106 | Fix issue when sequence is not working, skips next value 107 | ```sql 108 | SELECT max(gid) FROM geocoder LIMIT 1; 109 | 110 | SELECT nextval('geocoder_template_gid_seq'); 111 | ``` 112 | 113 | 2D Point as Lat & Lng 114 | ```sql 115 | SELECT ST_AsText('POINT(0 0'::geography); 116 | ``` 117 | 118 | 3D Point with Elevation 119 | ```sql 120 | SELECT ST_AsText('POINT(1 1 5)'::geography) AS pointz; 121 | ``` 122 | 123 | 3D Point with Elevation & Measurement 124 | ```sql 125 | SELECT ST_AsText('POINT(1 1 5 10)'::geography) AS pointzm; 126 | ``` 127 | 128 | Calculate Distance in meters between two points 129 | * Boolean True = Uses WGS84 Spheroid 130 | * Boolean False = Uses World Sphere, faster calculations, less accurate 131 | 132 | ```sql 133 | SELECT ST_Distance(point1, point2, true) AS distance 134 | FROM (SELECT 135 | 'POINT(0 0)'::geography AS point1, 136 | 'POINT(1 1)'::geography AS point2) AS foo; 137 | ``` 138 | 139 | Calculates the Distance between a Line to a Point 140 | ```sql 141 | SELECT ST_Distance( 142 | 'LINESTRING(0 0, 5 5)'::geography, 143 | 'POINT(3 3)'::geography); 144 | ``` 145 | 146 | Does this Polygon contain this point 147 | ```sql 148 | SELECT point 149 | FROM (SELECT 150 | 'POINT(5 5)'::geography AS point, 151 | 'POLYGON((0 0,0 10,10 10,10 0,0 0))'::geography AS poly) AS foo 152 | WHERE ST_Contains(poly, point); 153 | ``` 154 | 155 | Is Point within this Polygon 156 | ```sql 157 | SELECT point 158 | FROM (SELECT 159 | 'POINT(5 5)'::geography AS point, 160 | 'POLYGON((0 0,0 10,10 10,10 0,0 0))'::geography AS poly) AS foo 161 | WHERE ST_Within(point, poly); 162 | ``` 163 | 164 | Is Point within a Radius of another Point 165 | ```sql 166 | SELECT point 167 | FROM (SELECT 168 | 'POINT(5 5)'::geography AS point, 169 | 'POINT(3 3)'::geography AS center) AS foo 170 | WHERE ST_DWithin(point, center, 3.0); 171 | ``` 172 | 173 | WGS84 Data to Nad83 174 | ```sql 175 | SELECT ST_Transform(point, 4269) 176 | FROM (SELECT 177 | 'POINT(0 0)':geography AS point) AS Foo; 178 | ``` 179 | 180 | Distance between greater than 1000 meters 181 | ```sql 182 | SELECT ST_Distance(point1, point2) as distance 183 | FROM (SELECT 184 | 'POINT(0 0)'::geography as point1, 185 | 'POINT(1 1)'::geography as point2) AS Foo 186 | WHERE ST_Distance(point1, point2) > 1000 187 | ``` 188 | 189 | Normalize Address 190 | ```sql 191 | SELECT * FROM normalize_address('1552 Payette drive Ottawa ON'); 192 | SELECT * FROM normalize_address('K1E1S9'); 193 | ``` 194 | 195 | Fuzzy Matching 196 | ```sql 197 | SELECT soundex('Three'), soundex('Tree'), difference('Three', 'Tree'); 198 | ``` 199 | 200 | Index using GIST 201 | ```sql 202 | CREATE INDEX kingston_location_index ON kingston USING GIST(location) 203 | ``` 204 | 205 | Search Postal Codes 206 | ```sql 207 | select kingston.location, postal.fsa 208 | from kingston, postal 209 | WHERE ST_Contains(postal.geom, kingston.geom) 210 | ``` 211 | 212 | ## Table 213 | 214 | ```sql 215 | CREATE TABLE gtest( 216 | gid serial PRIMARY KEY, 217 | geom geography(POINT, 4326) 218 | ); 219 | ``` 220 | 221 | ```sql 222 | CREATE TABLE toronto( 223 | id int, 224 | x real, 225 | y real, 226 | geom geography(POINT, 4326), 227 | street_number int, 228 | street_name varchar(80), 229 | street_suffix varchar(10), 230 | street_side varchar(2) 231 | ); 232 | ``` 233 | ```sql 234 | CREATE TABLE toronto_google( 235 | id int, 236 | x real, 237 | y real, 238 | geom geography(POINT, 4326), 239 | street_number int, 240 | street_name varchar(80), 241 | types varchar(20), 242 | location_type varchar(20) 243 | ); 244 | ``` 245 | 246 | ## Insert 247 | 248 | ```sql 249 | INSERT INTO points(name, geom) 250 | VALUES('Denis', ST_GeomFromText('POINT(-71.060316 48.432044)', 4326)); 251 | ``` 252 | 253 | ```sql 254 | INSERT INTO gtest 255 | VALUES (3, 'First Geometry', ST_GeomFromText('LINESTRING(2 3,4 5,6 5,7 8)')); 256 | ``` 257 | 258 | ## Index 259 | 260 | ```sql 261 | CREATE INDEX gtest_index ON gtest USING GIST (geom); 262 | VACUUM ANALYZE; 263 | ``` 264 | 265 | ## Functions 266 | 267 | * ST_Distance() 268 | * ST_MaxDistance() 269 | * ST_Intersects() 270 | * ST_Contains() 271 | * ST_Within() 272 | * ST_Transform() 273 | 274 | ## Geometry Types 275 | 276 | * POINT(0 0) 277 | * POINTZ(0 0 0) 278 | * LINESTRING(0 0,1 1,1 2) 279 | * POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)) 280 | * MULTIPOINT(0 0,1 2) 281 | * MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4)) 282 | * MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1))) 283 | * GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4)) 284 | 285 | ## Projections 286 | 287 | - WGS84 => EPSG:4326 288 | - NAD83 => EPSG:4269 289 | - Web Mercator => EPSG:3857 290 | 291 | ## References 292 | 293 | * OpenGIS Consortium Standards 294 | * [PostGIS manual](http://postgis.net/docs/manual-2.0/PostGIS_FAQ.html) 295 | * [Open Geospatial standards](http://www.opengeospatial.org/standards/sfs) 296 | * International Standards SQL 92 & OGC-SFS 297 | * [Great Circle Mapper](http://gc.kls2.com/cgi-bin/gc?PATH=SEA-LHR) 298 | 299 | ## Accronyms 300 | 301 | * OGC-SFS (Open Geospatial Consortium - Simple Feature Specification) 302 | * SQL-92 (Structured Query Language) 303 | * ODBC (Open Database Connectivity) 304 | * API (Application Programming Interface) 305 | * RDBMS (Relational Database Management System) 306 | * WKB (Well-Known Binary) 307 | * WKT (Well-Known Text) 308 | * EWKT (Extended WKT) 309 | --------------------------------------------------------------------------------