Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1of 118

2009.foss4g.

org

Spatial Database
Tips & Tricks
Paul Ramsey
pramsey@opengeo.org

Housekeeping
Copy workshop from DVD
Download from
http://xx.xx.xx.xx/xxx/spdb-003.zip
Install or not
Ignore me or not
Examples also at
http://xx.xx.xx.xx:8080/spatialdbtips

Impatient People
They try to install without reading
instructions
When you see an error box during
PostGIS install, click Ignore
Remember to create medford
(not postgis) database during
PostGIS install

Impatient People

Its not dead, its just resting

Motivation
Spatial databases are powerful
Godlike, really
You do not need GIS software
Your database is GIS software
You do not need spatial
middleware
See above

Standard Database
Has data types

varchar
integer
real
date

Spatial Database
Has spatial data types

point
linestring
polygon
multipoint
multilinestring
multipolygon

Standard Database
Has one-dimensional indexes
b-tree
hash

Spatial Database
Has spatial indexes
r-tree
quad-tree
grid

Find intersecting shapes

Start with all boxes,

find intersecting boxes,

then find intersecting


shapes.

Standard Database
Has functions
Work against standard types

lower()
round()
substring()
trim()
dayofweek ()

Spatial Database
Has spatial functions
Work against spatial types

ST_Area(geometry)
ST_Distance(geometry,geometry)
ST_Intersects(geometry,geometry)
ST_DWithin(geometry,geometry,radius
)
ST_Union(geometry,geometry)

Open Geospatial Consortium (OGC)

Simple Features for SQL (SFSQL)

Spatial
Locator

LOCATOR

No buffer operation
No union operation
No intersection operation
No centroid point
No area or length calculation

SPATIAL
Linear referencing system (LRS) support
Spatial analysis and mining functions
and procedures (SDO_SAM package)
Geocoding support (SDO_GCDR
package)
GeoRaster support
Topology data model
Network data model

SFSQL compliant
New release, not as many features
No coordinate reference system
transforms
Windows only
Grid index

SELECT*FROMthe_table
WHEREST_Intersects(
the_geom,
ST_GeomFromText('POINT(00)',0)
);

SELECT*FROMthe_table
WHEREthe_geom.STIntersects(
geometry::STGeomFromText('POINT(00)',0)
);

PostgreSQL / PostGIS
SFSQL compliant
Open source (GPL)
Proprietary / open source clients
geographic coordinates require
care

ST_Distance(POINT(0 0),POINT(1 1))


What units?
ST_Distance_Spheroid()
ST_Distance_Sphere()
Indexes are not sphere aware
Spherical distance functions defined
on points only

Installation

Installation

Installation

Installation

Data

Data
Shape files
.shp, .shx, .dbf, .prj
shp2pgsql

Other?
FME
ogr2ogr

Tomcat
JNDI configured
o PostgreSQL JDBC
o Connection to medford database

JSLT installed
o <c:> <sql:>
GeoServer installed
o Connections to medford tables
o Styles for medford tables

Tomcat

Workshop

#0 - Base Map with WMS

http://localhost:8080/geoserver/

<bodyonload="init()">
<divid="map"></div>
</body>

varlon=122.8450;
varlat=42.3438;
varzoom=18;
varmap;
functioninitMap(){
map=newOpenLayers.Map('map',
{controls:[newOpenLayers.Control.MouseDefaults(),
newOpenLayers.Control.LayerSwitcher(),
newOpenLayers.Control.PanZoomBar()],
numZoomLevels:20});
vargmap=newOpenLayers.Layer.Google(
"GoogleStreets"//thedefault
);
vargsat=newOpenLayers.Layer.Google(
"GoogleSatellite",
{type:G_SATELLITE_MAP}
);
map.addLayers([gmap,gsat]);
map.setCenter(newOpenLayers.LonLat(lon,lat),zoom);
}

//InitializeWMSlayerfromourlocal
//GeoServer
varbwms=newOpenLayers.Layer.WMS(
"MedfordBuildings",
"http://localhost:8080/geoserver/wms?",
{"transparent":"true",
"layers":"medford:buildings",
"format":"image/png"},
{"reproject":"true"}
);
//AddWMSlayertoourmap
map.addLayer(bwms);

#1 Click to
Query

#1 Click to Query

//Tiethemapclickeventtoourqueryfunction
map.events.register("click",map,queryDatabase);

functionqueryDatabase(e){
//Readthemapcoordinatesfromtheclickevent
varlonlat=map.getLonLatFromViewPortPx(e.xy);
//Readthetablewearegoingtoqueryfrompage
vartable=document.getElementById("table").value;
//ConstructthequeryURL
varurl="01clickquery.jsp";
url+="?lon="+lonlat.lon;
url+="&lat="+lonlat.lat;
url+="&table="+table;
//LoadtheURLintoaniframe
document.getElementById("query").src=url;
}

01clickquery.jsp?
lon=122.8451943397522&
lat=42.344141057680226&
table=medford.taxlots

01-click-query.jsp
<%@tagliburi="http://java.sun.com/jsp/jstl/sql"prefix="sql"%>
<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>
<%@pagecontentType="text/html"%>
<sql:queryvar="rs"dataSource="jdbc/medford">
.......
</sql:query>

select
st_geometrytype(the_geom)asgeometrytype,
st_area(the_geom)asarea,
*
from${param.table}
where
st_contains(
the_geom,
st_transform(
st_setsrid(
st_makepoint(${param.lon},${param.lat}),
4326),
2270))

SRID?!?
Location = Coordinate + SRID
Here = (-121.92, 37.37) + EPSG:4326
ST_Transform() to change SRID
Store data in an efficient SRID
Transform inputs to your storage SRID
Transform outputs to your display SRID

#2 Click to
Analyze

02clickanalyze.jsp?
lon=122.8451943397522&
lat=42.344141057680226&
radius=200

select
count(*)as"NumberofLots",
round(avg(st_area(the_geom))::numeric/43560,1)||'acres'as
"AverageLotArea",
'$'||avg(impvalue)::integeras"AverageImprovementValue",
'$'||avg(landvalue)::integeras"AverageLandValue",
'$'||avg(impvalue+landvalue)::integeras"AverageTotal
Value",
avg(yearblt)::integeras"AverageYearBuilt"
frommedford.taxlots
where
st_dwithin(
taxlots.the_geom,
st_transform(
st_setsrid(
st_makepoint(${param.lon},${param.lat}),
4326),
2270),
${param.radius}
)

ST_DWithin()?!?
Indexed distance query
ST_Distance(g1,g2) < r
is not indexed
ST_DWithin(g1,g2,r)
is equivalent to
g1 && ST_Expand(g2,r) AND
ST_Distance(g1,g2) < r

#3 Click and Join

zoning

taxlots

Everything is related
to everything else,
but near things are
more related than
distant things.
- Waldo Tobler

Spatial relationships are a universal key for joining


otherwise disparate data.

zoning table
customer table

taxlot table

census table
road table
stream table

select
count(*)
asnum_lots,
sum(st_area(taxlot.the_geom))
astotal_lot_area,
zone.zoningaszoning,
sum(taxlot.landvalue)
astotal_land_value,
sum(taxlot.landvalue)/
sum(st_area(taxlot.the_geom))
asvalue_per_ft

from
medford.taxlotstaxlot
join
medford.zoningzone
on(
st_contains(
zone.the_geom,
st_centroid(taxlot.the_geom)
)
)

where
st_dwithin(
taxlot.the_geom,
st_transform(
st_setsrid(
st_makepoint(
${param.lon},
${param.lat}),
4326),
2270),
${param.radius}
)
groupbyzone.zoning
orderbytotal_lot_areadesc

#4 Click and
Union

ST_AsGeoJSON()
selectst_asgeojson(the_geom)
frommedford.streets
wherest_npoints(the_geom)<6
limit1;

GeoJSON Geometry
{"type":"MultiLineString",
"coordinates":[[
[4289753.869,253537.254],
[4290375.489,253518.361]
]]}

ST_As*()
Standard
ST_AsText() defined by OGC (SFSQL)
ST_AsBinary() defined by OGC (SFSQL)
ST_AsGML() defined by OGC (GML)

PostGIS
ST_AsKML() defined by Google (OGC)
ST_AsSVG() defined by W3C
ST_AsGeoJSON() defined by community

FeatureCollection

Feature
Geometry

Properties

Feature
Geometry

Properties

<%@tagliburi="http://java.sun.com/jsp/jstl/sql"prefix="sql"%>
<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>
<%@pagecontentType="text/xjson"%>
<sql:queryvar="rs"dataSource="jdbc/medford">
${param.sql}
</sql:query>
{"type":"FeatureCollection",
"features":[
<c:forEachvar="row"items="${rs.rows}"varStatus="rowStatus">
{"type":"Feature",
"geometry":<c:outvalue="${row.st_asgeojson}"escapeXml="false"/>,
"properties":{
<c:forEachvar="column"items="${row}"varStatus="columnStatus">
<c:iftest="${column.key!='st_asgeojson'}">
"<c:outvalue="${column.key}"escapeXml="false"/>":
"<c:outvalue="${column.value}"escapeXml="false"/>"
<c:iftest="${!columnStatus.last}">,</c:if>
</c:if>
</c:forEach>
}}
<c:iftest="${!rowStatus.last}">,</c:if>
</c:forEach>
]}

selectst_asgeojson(
st_transform(the_geom,900913)
)
frommedford.taxlots
where
st_dwithin(
the_geom,
st_transform(
st_setsrid(
st_makepoint(13676108,5212594),
900913),
2270),
100
)

//Makeafreshvectorlayer,pullingfeaturesourURL
json_layer=newOpenLayers.Layer.Vector("GeoJSON",{
strategies:[newOpenLayers.Strategy.Fixed()],
protocol:newOpenLayers.Protocol.HTTP({
url:json_url,
format:newOpenLayers.Format.GeoJSON()
})
});
//Addourvectorlayertothemap
map.addLayer(json_layer);

#5 Arbitrary SQL

#6 Walk a
Network

medford.storm_drains
node_fm

node_to

medford.storm_drains
id

node_fm

node_to

9105
8

D372W25CN016
9

D372W25CN016
8

id

node_fm

node_to

9106
1

D372W25CN016
8

D372W25CN016
7

id

node_fm

node_to

9106
2

D372W25CN016
7

D372W25CN016
6

selectd.node_fm,d.node_to,d.pipe_id
from
medford.storm_drainsd,
medford.storm_drainse
wherest_dwithin(d.the_geom,e.the_geom,5)
ande.node_to='D371W28CN0134'
ande.gid!=d.gid
andst_distance(
st_endpoint(st_geometryn(e.the_geom,1)),
st_startpoint(st_geometryn(d.the_geom,1))
)<5;

e.node_to='D371W28CN0134'

ST_DWithin()

ST_DWithin()

e.gid != d.gid

st_distance(
st_endpoint(st_geometryn(e.the_geom,
1)),
st_startpoint(st_geometryn(d.the_geom,
1))
) < 5;

st_distance(
st_endpoint(st_geometryn(e.the_geom,
1)),
st_startpoint(st_geometryn(d.the_geom,
1))
) < 5;

ST_GeometryN()
Convert
MULTILINESTRING((0 0, 1 1, 2 2))

To
LINESTRING(0 0, 1 1, 2 2)

In conclusion

Standards are good


SFSQL
KML
GML

GeoJSON
WKB

WMS
WKT
WFS

Special middleware is
unnecessary

2009.foss4g.org

You might also like