Retrieving GIS Data

Data can be extracted from the database using either SQL or the Shape file loader/dumper. In the section on SQL we will discuss some of the operators available to do comparisons and queries on spatial tables.

Using SQL

The most straightforward means of pulling data out of the database is to use a SQL select query and dump the resulting columns into a parsable text file:

db=# SELECT id, AsText(geom) AS geom, name FROM ROADS_GEOM; 
id | geom                                    | name 
---+-----------------------------------------+-----------
 1 | LINESTRING(191232 243118,191108 243242) | Jeff Rd  
 2 | LINESTRING(189141 244158,189265 244817) | Geordie Rd 
 3 | LINESTRING(192783 228138,192612 229814) | Paul St 
 4 | LINESTRING(189412 252431,189631 259122) | Graeme Ave 
 5 | LINESTRING(190131 224148,190871 228134) | Phil Tce 
 6 | LINESTRING(198231 263418,198213 268322) | Dave Cres 
(6 rows)

However, there will be times when some kind of restriction is necessary to cut down the number of fields returned. In the case of attribute-based restrictions, just use the same SQL syntax as normal with a non-spatial table. In the case of spatial restrictions, the following operators are available/useful:

&&

This operator tells whether the bounding box of one geometry overlaps the bounding box of another.

~=

This operators tests whether two geometries are geometrically identical. For example, if 'POLYGON((0 0,1 1,1 0,0 0))' is the same as 'POLYGON((0 0,1 1,1 0,0 0))' (it is).

=

This operator is a little more naive, it only tests whether the bounding boxes of to geometries are the same.

Next, you can use these operators in queries. Note that when specifying geometries and boxes on the SQL command line, you must explicitly turn the string representations into geometries by using the "GeometryFromText()" function. So, for example:

SELECT ID, NAME FROM ROADS_GEOM 
  WHERE GEOM ~= GeometryFromText('LINESTRING(191232 243118,191108 243242)',-1);

The above query would return the single record from the "ROADS_GEOM" table in which the geometry was equal to that value.

When using the "&&" operator, you can specify either a BOX3D as the comparison feature or a GEOMETRY. When you specify a GEOMETRY, however, its bounding box will be used for the comparison.

SELECT ID, NAME FROM ROADS_GEOM 
  WHERE GEOM && GeometryFromText('POLYGON((191232 243117,191232 243119,191234 243117,191232 243117))',-1);

The above query will use the bounding box of the polygon for comparison purposes.

The most common spatial query will probably be a "frame-based" query, used by client software, like data browsers and web mappers, to grab a "map frame" worth of data for display. Using a "BOX3D" object for the frame, such a query looks like this:

SELECT AsText(GEOM) AS GEOM FROM ROADS_GEOM 
  WHERE GEOM && GeometryFromText('BOX3D(191232 243117,191232 243119)',-1);

Note the use of the SRID, to specify the projection of the BOX3D. The -1 is used to indicate no specified SRID.

Using the Dumper

This section to be written.

Using Minnesota Mapserver

The Minnesota Mapserver is an internet web-mapping server. The latest versions conform to the OpenGIS Web Map Specification.

To use PostGIS with Mapserver, you will need to know about how to configure Mapserver, which is beyond the scope of this documentation. This section will cover specific PostGIS issues and configuration details.

To use PostGIS with Mapserver, you will need:

Mapserver accesses PostGIS/PostgreSQL data like any other PostgreSQL client -- using libpq. This means that Mapserver can be installed on any machine with network access to hte PostGIS server, as long as the system has the libpq PostgreSQL client libraries.

  1. Compile and install Mapserver, with whatever options you desire, including the "--with-postgis" configuration option.

  2. In your Mapserver map file, add a PostGIS layer. For example:

      LAYER
        CONNECTIONTYPE postgis
        NAME "widehighways"
        # Connect to a remote spatial database
        CONNECTION "user=dbuser dbname=gisdatabase host=bigserver"
        # Get the lines from the 'geom' column of the 'roads' table
        DATA "geom from roads"
        STATUS ON
        TYPE LINE
        # Of the lines in the extents, only render the wide highways
        FILTER "type = 'highway' and numlanes >= 4"
        CLASS
          # Make the superhighways brighter and 2 pixels wide
          EXPRESSION ([numlanes] >= 6)
          COLOR 255 22 22      
          SYMBOL "solid"
          SIZE 2
        END
        CLASS
          # All the rest are darker and only 1 pixel wide
          EXPRESSION ([numlanes] < 6)
          COLOR 205 92 82      
        END
      END

    In the example above, the PostGIS-specific directives are as follows:

    CONNECTIONTYPE

    For PostGIS layers, this is always "postgis".

    CONNECTION

    The database connection is governed by the a 'connection string' which is a standard set of keys and values like this (with the default values in <>):

    user=<username> password=<password> dbname=<username> hostname=<server> port=<5432>

    An empty connection string is still valid, and any of the key/value pairs can be omitted. At a minimum you will generally supply the database name and username to connect with.

    DATA

    The form of this parameter is "<column> from <tablename>" where the column is the spatial column to be rendered to the name.

    FILTER

    The filter must be a valid SQL string corresponding to the logic normally following the "WHERE" keyword in a SQL query. So, for example, to render only roads with 6 or more lanes, use a filter of "num_lanes >= 6".

  3. In your spatial database, ensure you have spatial (GiST) indexes built for any the layers you will be drawing.

  4. If you will be querying your layers using Mapserver you will also need an "oid index".

    Mapserver requires unique identifiers for each spatial record when doing queries, and the PostGIS module of Mapserver uses the PostgreSQL oid value to provide these unique identifiers. A side-effect of this is that in order to do fast random access of records during queries, an index on the oid is needed.

    To build an "oid index", use the following SQL:

      CREATE INDEX <indexname> ON <tablename> ( oid );