Professional Documents
Culture Documents
Spatial Database Tips and Tricks Presentation
Spatial Database Tips and Tricks Presentation
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
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
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)
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
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
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
zoning
taxlots
Everything is related
to everything else,
but near things are
more related than
distant things.
- Waldo Tobler
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
GeoJSON
WKB
WMS
WKT
WFS
Special middleware is
unnecessary
2009.foss4g.org