<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-15655029</id><updated>2011-04-21T17:00:50.602-05:00</updated><title type='text'>SQL for Geographers</title><subtitle type='html'>This blog is dedicated to the integration between GIS and enterprise level relational databases.  The amount of data waiting to be spatially enabled within enterprise databases is extraordinary. I hope to show in this blog working examples of database-GIS interaction.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://geosql.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://geosql.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jeremy</name><uri>http://www.blogger.com/profile/06135435775056095723</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-15655029.post-115038743842667999</id><published>2006-06-15T10:39:00.000-05:00</published><updated>2006-06-15T11:03:58.583-05:00</updated><title type='text'>Oracle Spatial + Where 2.0?</title><content type='html'>Ok...&lt;br /&gt;&lt;br /&gt;So I just got back from the Where 2.0 conference.  All in all it was a pretty good show.  I have my issues with some of the talks, but overall it was really good.  The question I have is.  &lt;span style="font-style: italic;"&gt;Where was Oracle?&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;Don't you think that Oracle Spatial should have been there?&lt;br /&gt;&lt;br /&gt;Maybe I missed them, but they were not presenting and they were not in the participant list.&lt;br /&gt;&lt;br /&gt;Intel, Google, Yahoo, Microsoft, Autodesk, ESRI, MapInfo, Ask, AOL, Cisco, Motorola, MapQuest, eBay, Apple, and many others were there.&lt;br /&gt;&lt;br /&gt;Some presenters really talked about Oracle Spatial though...&lt;br /&gt;&lt;br /&gt;Jeremy&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15655029-115038743842667999?l=geosql.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geosql.blogspot.com/feeds/115038743842667999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=15655029&amp;postID=115038743842667999' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/115038743842667999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/115038743842667999'/><link rel='alternate' type='text/html' href='http://geosql.blogspot.com/2006/06/oracle-spatial-where-20.html' title='Oracle Spatial + Where 2.0?'/><author><name>Jeremy</name><uri>http://www.blogger.com/profile/06135435775056095723</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15655029.post-114479206731332148</id><published>2006-04-11T16:41:00.000-05:00</published><updated>2006-04-11T22:08:45.503-05:00</updated><title type='text'>Consuming REST services with Oracle</title><content type='html'>&lt;span style="color: rgb(0, 0, 0);font-family:arial;" &gt;I love &lt;/span&gt;&lt;a style="font-family: arial; color: rgb(51, 102, 255);" href="http://webservices.xml.com/pub/a/ws/2002/02/06/rest.html"&gt;REST&lt;/a&gt;&lt;span style="color: rgb(0, 0, 0);font-family:arial;" &gt; services (representation state transfer).   They provide a powerful yet simple way of consuming data via the web (Some examples of REST services:  &lt;a href="http://developer.yahoo.com/search/index.html"&gt;Yahoo&lt;/a&gt;, some &lt;a href="http://ashburnarcweb.esri.com/v2006/develop/rest.jsp"&gt;ArcWeb Services&lt;/a&gt;, &lt;a href="http://www.mapdex.org/cfcdoc/mapdex.html"&gt;Mapdex API&lt;/a&gt;, &lt;a href="http://www.flickr.com/services/api/request.rest.html"&gt;Flickr&lt;/a&gt;, even &lt;a href="http://portal.opengeospatial.org/files/?artifact_id=14416"&gt;WMS &lt;/a&gt;services).    Here is an example of one I made up.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:arial;" &gt;I want to be able to query the National Elevation Dataset (via http://seamless.usgs.gov ) to find out what the elevation is at a particular latitude, longitude coordinate.  I want to submit a geographic point and extract the elevation value at the point.  USGS is publishing this as an ArcIMS image service &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);font-family:arial;" &gt;(&lt;a href="http://www.mapdex.org/getserviceinfo_style.cfm?server_id=ortho.cr.usgs.gov&amp;service_name=USGS_EDC_Elev_NED&amp;amp;server_ip=152.61.128.152"&gt;USGS_EDC_Elev_NED&lt;/a&gt;)&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);font-family:arial;" &gt;.     I can use the &lt;a href="http://edndoc.esri.com/arcims/9.1/elements/get_raster_info.htm"&gt;get_raster_info&lt;/a&gt; request to extract the elevation at a particular point.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://hercules.kgs.ku.edu/kgs/web_services/NED_REST/seamless_ned_elevation.cfm?latitude=38&amp;longitude=-115&amp;amp;mapserver=seamless.usgs.gov&amp;mapservice=USGS_EDC_Elev_NED&amp;amp;layer_id=NED.CONUS_NED"&gt;Here&lt;/a&gt; is my test REST service:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:arial;" &gt;&lt;pre&gt;http://hercules.kgs.ku.edu/kgs/web_services/NED_REST/seamless_ned_elevation.cfm?&lt;br /&gt;latitude=38&amp;longitude=-115&lt;br /&gt;&amp;amp;mapserver=seamless.usgs.gov&lt;br /&gt;&amp;mapservice=USGS_EDC_Elev_NED&lt;br /&gt;&amp;amp;layer_id=NED.CONUS_NED&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:arial;" &gt;&lt;br /&gt;You can view the source code &lt;a href="http://hercules.kgs.ku.edu/kgs/web_services/NED_REST/seamless_ned_elevation.txt"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It queries the service and reformats the ArcIMS response to the following XML output:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt;&amp;lt;NED_ELEVATION&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt; &amp;lt;ELEVATION_LOCATION latitude="38" longitude="-115"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt;   &amp;lt;ELEVATION_METERS&amp;gt;1627.53918457031&amp;lt;/ELEVATION_METERS&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt;   &amp;lt;ELEVATION_FEET&amp;gt;5339.95606458&amp;lt;/ELEVATION_FEET&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt; &amp;lt;/ELEVATION_LOCATION&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt;&amp;lt;/NED_ELEVATION&amp;gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;In order to access this document in Oracle we need to take advantage of two features.  One is the utl_http package (see &lt;a href="http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:285215954607"&gt;AskTom&lt;/a&gt; or the Oracle docs for more info) to request an html page via a url.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/utl_http.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/utl_http.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt;&lt;span style="font-family:arial;"&gt;&lt;span style="font-family:arial;"&gt;This query will actually return the text/xml response from the server as a 4000 character string to the sqlplus window (use request_pieces for larger files).&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:arial;"&gt;We then have to turn this character representation into an xml document so we can query it.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt;&lt;span style="font-family:arial;"&gt;To do this we can use the &lt;a href="http://www.oracle.com/technology/oramag/oracle/01-nov/o61xml.html"&gt;xmltype&lt;/a&gt; datatype (an Oracle system defined datatype) that allows us to parse an xml document and query it via xpath.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt;&lt;span style="font-family:arial;"&gt;&lt;br /&gt;Since my REST service returns an xml document all we have to do is store the xml document as an xmltype datatype and use xpath to query the xml document to retrieve the relevant values.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;select a.xmldataout.extract&lt;br /&gt;('//KANSAS_ELEVATION/ELEVATION_LOCATION/ELEVATION_FEET/text()').getNumberVal()&lt;br /&gt;as elevation_feet,  &lt;br /&gt;a.xmldataout.extract&lt;br /&gt;('//KANSAS_ELEVATION/ELEVATION_LOCATION/ELEVATION_METERS/text()').getNumberVal()&lt;br /&gt;as elevation_meters&lt;br /&gt;from (select&lt;br /&gt;xmltype(UTL_HTTP.REQUEST&lt;br /&gt;       ('http://geoportal.kgs.ku.edu/kgs/web_services/kansas_elevation/&lt;br /&gt;         ks_ned_elevation_datum.cfm?latitude=39.1&amp;longitude=-99.6&amp;amp;datum=27'&lt;br /&gt;       )&lt;br /&gt;) xmldataout from dual) a&lt;br /&gt;where a.xmldataout.extract('//KANSAS_ELEVATION/ERROR/text()').getStringVal() is null&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Which returns...&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;pre&gt;ELEVATION_FEET ELEVATION_METERS&lt;br /&gt;-------------- ----------------&lt;br /&gt;2886.25208       879.686707&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;Do you see the power?  I can do this for single point or as an update to an entire table.&lt;br /&gt;&lt;br /&gt;So now I can map the elevation along my run route...&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/run_elevation.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/run_elevation.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:courier new;" &gt;&lt;span style="font-family:arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15655029-114479206731332148?l=geosql.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geosql.blogspot.com/feeds/114479206731332148/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=15655029&amp;postID=114479206731332148' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/114479206731332148'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/114479206731332148'/><link rel='alternate' type='text/html' href='http://geosql.blogspot.com/2006/04/consuming-rest-services-with-oracle.html' title='Consuming REST services with Oracle'/><author><name>Jeremy</name><uri>http://www.blogger.com/profile/06135435775056095723</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15655029.post-114360359424135551</id><published>2006-03-28T20:39:00.000-06:00</published><updated>2006-03-28T23:27:00.903-06:00</updated><title type='text'>Database + GIS = Powerful Visualization</title><content type='html'>I love GIS.  Here are two flat Oracle tables one describing the top values (depth to a particular formation) for all the wells in Kansas the other summarizing the amount of production by section (PLSS square mile), by year, by type (oil or gas), and by formation.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SQL&gt; desc STRAT_WELL_TOP_22MAR2006&lt;br /&gt;Name                               Null?    Type&lt;br /&gt;---------------------------------- -------- ------------------&lt;br /&gt;FORMATION_NAME                     NOT NULL VARCHAR2(60)&lt;br /&gt;WELL_HEADER_KID                    NOT NULL NUMBER(10)&lt;br /&gt;WELL_TOP                                    NUMBER(8,2)&lt;br /&gt;FIELD_KID                                   NUMBER(10)&lt;br /&gt;LATITUDE                                    NUMBER(11,6)&lt;br /&gt;LONGITUDE                                   NUMBER(11,6)&lt;br /&gt;GROUND_ELEVATION                            VARCHAR2(40)&lt;br /&gt;GROUND_ELEVATION_SOURCE                     VARCHAR2(12)&lt;br /&gt;WELL_TOP_SEALEVEL_NON_NED                   VARCHAR2(40)&lt;br /&gt;WELL_TOP_SEALEVEL                           NUMBER&lt;br /&gt;&lt;br /&gt;SQL&gt; desc ACRES_640_PRODUCTION_FORMATION&lt;br /&gt;Name                                     Null?    Type&lt;br /&gt;---------------------------------------- -------- -------------&lt;br /&gt;RECNMBR                                  NOT NULL NUMBER(11)&lt;br /&gt;STRAT_UNIT_KID                           NOT NULL NUMBER(10)&lt;br /&gt;YEAR                                     NOT NULL NUMBER(4)&lt;br /&gt;PRODUCT                                  NOT NULL VARCHAR2(1)&lt;br /&gt;PRODUCTION                                        NUMBER(12,2)&lt;br /&gt;&lt;/pre&gt;The goal is to produce a multipatch polygon between two formations colored by the cummulative amount of oil and gas production between the formaitons.  Today I built a geoprocessing model to accomplish this task.   Here are the steps I need to...&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Select records for two distinct formations,&lt;/li&gt;&lt;li&gt;Generate event themes based on the x,y coordinates of the records in step 1,&lt;/li&gt;&lt;li&gt;Generate two distinct TIN representations of the x,y,z values,&lt;/li&gt;&lt;li&gt;Create a view that summarizes the production between the two formations by section and join that datasaet to a spatial layer depicting the sections,&lt;/li&gt;&lt;li&gt;Use the &lt;a href="http://edndoc.esri.com/arcobjects/9.1/default.asp?url=/arcobjects/9.1/ComponentHelp/esriGeometry/IExtrude_ExtrudeBetween.htm"&gt;extrude between&lt;/a&gt; process to generate a multi-patch polygon using the two tin datasets as the top and bottom surfaces clipped by the section production.&lt;/li&gt;&lt;/ol&gt;Anyway enough talk...Here is the model:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/top_extrude_model.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/top_extrude_model.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And here is the output...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/view3d.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/view3d.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The cool thing about the model is that I can rerun it based on any input query (set of formations).  Build once, run everywhere.&lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;&lt;br /&gt;Jeremy&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15655029-114360359424135551?l=geosql.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geosql.blogspot.com/feeds/114360359424135551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=15655029&amp;postID=114360359424135551' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/114360359424135551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/114360359424135551'/><link rel='alternate' type='text/html' href='http://geosql.blogspot.com/2006/03/database-gis-powerful-visualization.html' title='Database + GIS = Powerful Visualization'/><author><name>Jeremy</name><uri>http://www.blogger.com/profile/06135435775056095723</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15655029.post-114287459634169789</id><published>2006-03-20T11:01:00.000-06:00</published><updated>2006-03-20T11:11:25.543-06:00</updated><title type='text'>SQL Interpolation Techniques</title><content type='html'>First off I have just returned from the ESRI developers summit and I had a great time.  It was so nice to meet all the great developers out there.  ESRI did a great job in organizing it.  If you ever get a chance to meet &lt;a href="http://www.spatialdatalogic.com/cs/blogs/brian_flood/default.aspx"&gt;Brian Flood&lt;/a&gt; take advantage of it.  Brian is an amazing developer and I really enjoyed our coversations.  Brian gets it...&lt;br /&gt;&lt;br /&gt;I file this one under, stop me before I try to do too much with SQL!  I wrote this a couple of years ago when I wanted have an interpolation routine that was straight SQL (No Oracle Spatial and No SDE).  I would not do this technique now (ESRI Spatial Type for Oracle or straight to ArcGIS Server for my interpolations) but it illustrates some good Analytical Function practices.  Enjoy...&lt;br /&gt;&lt;br /&gt;&lt;PRE&gt;ORIGINAL QUESTION:&lt;br /&gt;&lt;br /&gt;I have a table that represents one mile polygons (sections) that has locational &lt;br /&gt;information, center latitude and center longitude.  I have another table that is &lt;br /&gt;made up of point data that has for every point the latitude, longitude, and some&lt;br /&gt;value (lets say it is a water level depth).  What I want to do is build a view &lt;br /&gt;that has the section polygon ID and an average water level value for the closest &lt;br /&gt;10 wells that are at least within 10 square miles.  This involves computing the &lt;br /&gt;distance of all wells within a 10 square mile of the polygon cell, sorting those &lt;br /&gt;wells to find the closest 10, and then averaging the results (actually I would &lt;br /&gt;perform some kind of inverse distance calculation, but for simplicity sake I &lt;br /&gt;would like to see how you would  efficiently select and average the 10 wells &lt;br /&gt;values). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I HAVE PASTED MY ATTEMPT BELOW...&lt;br /&gt;&lt;br /&gt;HERE IS INFORMATION ABOUT THE TWO TABLES THAT QUERY USES.  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; DESC ACRES640_XYCENTER&lt;br /&gt; Name                                      Null?    Type&lt;br /&gt; ----------------------------------------- -------- ----------------------------&lt;br /&gt; OBJECTID                                  NOT NULL NUMBER(38)&lt;br /&gt; TRS                                                VARCHAR2(10)&lt;br /&gt; RECNMBR                                            NUMBER(11)&lt;br /&gt; CENTER_X                                           NUMBER(23,11)&lt;br /&gt; CENTER_Y                                           NUMBER(23,11)&lt;br /&gt; SHAPE                                              NUMBER(38)&lt;br /&gt;&lt;br /&gt;SQL&gt; select trs, recnmbr, center_x, center_y from ACRES640_XYCENTER where rownum &lt; 10;&lt;br /&gt;&lt;br /&gt;TRS           RECNMBR   CENTER_X   CENTER_Y                                     &lt;br /&gt;---------- ---------- ---------- ----------                                     &lt;br /&gt;02S22W08         2816    -133815     431037                                     &lt;br /&gt;02S05E07         2817     114097     430710                                     &lt;br /&gt;02S12E07         2818     181440     431992                                     &lt;br /&gt;02S03W08         2819    48505.5     430018                                     &lt;br /&gt;02S23W12         2820    -136969     431089                                     &lt;br /&gt;02S05W08         2821 29424.6992     429929                                     &lt;br /&gt;02S04E12         2822     112494     430684                                     &lt;br /&gt;02S25W10         2823    -159307     431515                                     &lt;br /&gt;02S10E07         2824     162297     431573                                     &lt;br /&gt;&lt;br /&gt;9 rows selected.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; SELECT COUNT(*) FROM ACRES640_XYCENTER;&lt;br /&gt;&lt;br /&gt;  COUNT(*)                                                                      &lt;br /&gt;----------                                                                      &lt;br /&gt;     81803                                                                      &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; desc WELLHEADERS_25MAY2004_PRJ&lt;br /&gt; Name                                      Null?    Type&lt;br /&gt; ----------------------------------------- -------- ----------------------------&lt;br /&gt; OBJECTID                                  NOT NULL NUMBER(38)&lt;br /&gt; KID                                                NUMBER(10)&lt;br /&gt; LATITUDE                                           NUMBER(17,6)&lt;br /&gt; LONGITUDE                                          NUMBER(17,6)&lt;br /&gt; X_COORD                                            NUMBER(23,11)&lt;br /&gt; Y_COORD                                            NUMBER(23,11)&lt;br /&gt; SHAPE                                              NUMBER(38)&lt;br /&gt;&lt;br /&gt;     &lt;br /&gt;&lt;br /&gt;SQL&gt; select kid, latitude, longitude, x_coord, y_coord from WELLHEADERS_25MAY2004_PRJ;&lt;br /&gt;&lt;br /&gt;       KID   LATITUDE  LONGITUDE    X_COORD    Y_COORD                          &lt;br /&gt;---------- ---------- ---------- ---------- ----------                          &lt;br /&gt;1027937589   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027937587   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027937585   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027937583   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027937567   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027937237   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027937235   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027935075   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027803979   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027936869   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027936867   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027936865   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027936805   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027937057   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027934581   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027934579   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027934577   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027934575   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027934573   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027934571   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027934569   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027804273   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1027804269   37.00094  -95.77342     219360     113565                          &lt;br /&gt;1006790617   37.00133  -96.08868     191441     112895                          &lt;br /&gt;1002895443   37.00133  -96.21841     179952     112630                          &lt;br /&gt;1006790402   37.00133  -96.21841     179952     112630                          &lt;br /&gt;1001257052   37.00132 -101.97293    -329700     117372                          &lt;br /&gt;1006094323   37.00132 -101.97293    -329700     117372                          &lt;br /&gt;1006094606   37.00132 -101.97746    -330101     117389                          &lt;br /&gt;1020067001   37.00132 -101.97746    -330101     117389                          &lt;br /&gt;1005449837   37.00132 -101.97746    -330101     117389                          &lt;br /&gt;1026090216    37.0013 -100.57895    -206286     113259                          &lt;br /&gt;1006093808    37.0013 -100.57895    -206286     113259                          &lt;br /&gt;1026525325    37.0013 -100.57895    -206286     113259                          &lt;br /&gt;1027805483   37.00128  -95.84634     212901     113429                          &lt;br /&gt;1027937579   37.00128  -95.84634     212901     113429                          &lt;br /&gt;1027807657   37.00128  -95.84634     212901     113429                          &lt;br /&gt;1027807573   37.00128  -95.84634     212901     113429                          &lt;br /&gt;1027807185   37.00128  -95.84634     212901     113429                          &lt;br /&gt;1027703233   37.00128  -98.83632 -51938.301     110781                          &lt;br /&gt;1027796075   37.00128  -98.83632 -51938.301     110781                          &lt;br /&gt;1002901280   37.00127  -97.07416     104158     111286                          &lt;br /&gt;1008415306   37.00127 -101.51646    -289294     115812                          &lt;br /&gt;1027807735   37.00122  -95.82817     214511     113465                          &lt;br /&gt;1027805485   37.00122  -95.82817     214511     113465                          &lt;br /&gt;1027807499   37.00122  -95.82817     214511     113465                          &lt;br /&gt;1027806799   37.00122  -95.82817     214511     113465                          &lt;br /&gt;1027806797   37.00122  -95.82817     214511     113465                          &lt;br /&gt;1027806517   37.00122  -95.82817     214511     113465                          &lt;br /&gt;1027805877   37.00122  -95.82817     214511     113465                          &lt;br /&gt;1006143725   37.00122 -100.71236    -218100     113562                          &lt;br /&gt;1002932550    37.0012  -95.81286     215866     113499                          &lt;br /&gt;1006790987   37.00119  -95.80991     216128     113505                          &lt;br /&gt;1005456974   37.00119  -95.80991     216128     113505                          &lt;br /&gt;1027805555   37.00119  -95.80992     216127     113505                          &lt;br /&gt;1006790391   37.00111  -96.19579     181955     112651                          &lt;br /&gt;1002895619   37.00111  -96.41649     162409     112233                          &lt;br /&gt;1006790787    37.0011   -95.9109     207185     113260                          &lt;br /&gt;1027805141   37.00109  -95.79157     217752     113538                          &lt;br /&gt;1027805077   37.00109  -95.79157     217752     113538                          &lt;br /&gt;1027931973   37.00109  -95.79157     217752     113538                          &lt;br /&gt;1027931971   37.00109  -95.79157     217752     113538                          &lt;br /&gt;1027806551   37.00109  -95.79157     217752     113538                          &lt;br /&gt;1004751365   37.00159 -101.81951    -316120     116857                          &lt;br /&gt;1002876182   37.00159 -101.82404    -316521     116873                          &lt;br /&gt;1002895677   37.00158  -96.26826     175536     112560                          &lt;br /&gt;1002952960   37.00158  -97.65121 53042.6992     110821                          &lt;br /&gt;&lt;br /&gt;68 rows selected.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; SELECT COUNT(*) FROM WELLHEADERS_25MAY2004_PRJ;&lt;br /&gt;&lt;br /&gt;  COUNT(*)                                                                      &lt;br /&gt;----------                                                                      &lt;br /&gt;    375571                                                                      &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SQL&gt; &lt;br /&gt;SQL&gt; COLUMN COLUMN_NAME FORMAT A15 TRUNC&lt;br /&gt;SQL&gt; ;&lt;br /&gt;  1  SELECT INDEX_NAME, COLUMN_NAME, TABLE_NAME FROM USER_IND_COLUMNS&lt;br /&gt;  2* WHERE TABLE_NAME IN ('WELLHEADERS_25MAY2004_PRJ','ACRES640_XYCENTER')&lt;br /&gt;SQL&gt; /&lt;br /&gt;&lt;br /&gt;INDEX_NAME                     COLUMN_NAME     TABLE_NAME                       &lt;br /&gt;------------------------------ --------------- ------------------------------   &lt;br /&gt;A1411_IX1                      SHAPE           ACRES640_XYCENTER                &lt;br /&gt;R2067_SDE_ROWID_UK             OBJECTID        ACRES640_XYCENTER                &lt;br /&gt;ACRES640_XYCENTER_RECNMBR      RECNMBR         ACRES640_XYCENTER                &lt;br /&gt;ACRES640_XYCENTER_X_YCENT      CENTER_X        ACRES640_XYCENTER                &lt;br /&gt;ACRES640_XYCENTER_X_YCENT      CENTER_Y        ACRES640_XYCENTER                &lt;br /&gt;ACRES640_XYCENTER_CENTX        CENTER_X        ACRES640_XYCENTER                &lt;br /&gt;ACRES640_XYCENTER_CENTY        CENTER_Y        ACRES640_XYCENTER                &lt;br /&gt;A1409_IX1                      SHAPE           WELLHEADERS_25MAY2004_PRJ        &lt;br /&gt;R2065_SDE_ROWID_UK             OBJECTID        WELLHEADERS_25MAY2004_PRJ        &lt;br /&gt;WELLHEADERS_25_MAY2004KID      KID             WELLHEADERS_25MAY2004_PRJ        &lt;br /&gt;WELLHEADERS_25_MAY2004_LATLONG Y_COORD         WELLHEADERS_25MAY2004_PRJ        &lt;br /&gt;WELLHEADERS_25_MAY2004_LATLONG X_COORD         WELLHEADERS_25MAY2004_PRJ        &lt;br /&gt;WELLHEADERS_25_MAY2004_YCOORD  Y_COORD         WELLHEADERS_25MAY2004_PRJ        &lt;br /&gt;WELLHEADERS_25_MAY2004_XCOORD  X_COORD         WELLHEADERS_25MAY2004_PRJ        &lt;br /&gt;&lt;br /&gt;14 rows selected.&lt;br /&gt;&lt;br /&gt;                                               &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;HERE IS THE QUERY THAT I CAME UP WITH....&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;FIRST I WANT TO SELECT THE SECTION ID, WELL ID, THE DISTANCE FROM THE WELL TO THE &lt;br /&gt;CENTER OF THE SECTION, &amp; THE QUADRANT OF THE SECTION (NW,NE,SW,SE) THAT THE WELL&lt;br /&gt;IS IN ALL WITHIN A 7200 X 7200 METER BOUDING BOX (CENTERED ON THE SECTION CENTER) &lt;br /&gt;FOR EVERY SECTION IN MY STUDY AREA.  &lt;br /&gt;&lt;br /&gt;  select a.recnmbr recnmbr, b.kid kid,&lt;br /&gt;    case &lt;br /&gt;    when b.x_coord &lt; a.center_x and b.Y_COORD &lt; a.center_y then 'SW'&lt;br /&gt;    when b.x_coord &lt; a.center_x and b.Y_COORD &gt; a.center_y then 'NW'&lt;br /&gt;    when b.x_coord &gt; a.center_x and b.Y_COORD &lt; a.center_y then 'SE'&lt;br /&gt;    when b.x_coord &gt; a.center_x and b.Y_COORD &gt; a.center_y then 'NE'&lt;br /&gt;     end QUADRANT,&lt;br /&gt;  sqrt( ( (b.x_coord - a.center_x) * (b.x_coord - a.center_x) ) + &lt;br /&gt;      ( (b.Y_COORD - a.center_y) * (b.Y_COORD - a.center_y) ) ) distance_to_cell&lt;br /&gt;    from ACRES640_XYCENTER a, WELLHEADERS_25MAY2004_PRJ b&lt;br /&gt;   where b.y_coord between a.center_y - 3600 and a.center_y + 3600 &lt;br /&gt;     and b.x_coord between a.center_x - 3600  and a.center_x + 3600 &lt;br /&gt;     and a.center_x &gt;= -320688&lt;br /&gt;     and a.center_x &lt;= -284100&lt;br /&gt;     and a.center_y &gt;= 169518&lt;br /&gt;     and a.center_y &lt;= 242855 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   RECNMBR        KID QU DISTANCE_TO_CELL&lt;br /&gt;---------- ---------- -- ----------------&lt;br /&gt;     49950 1006068633 SW       4129.70144&lt;br /&gt;     49950 1006068137 SW       3580.94959&lt;br /&gt;     49950 1002919963 SW       4519.08055&lt;br /&gt;     49950 1006068032 SE       3446.22605&lt;br /&gt;     49950 1006068206 SW       2316.18501&lt;br /&gt;     49950 1022362561 SW       3422.35124&lt;br /&gt;     49950 1006068139 SW       1594.49365&lt;br /&gt;     49950 1001235397 SW       3128.24951&lt;br /&gt;     49950 1022009618 SW       2460.49934&lt;br /&gt;     49950 1006068479 SW       1646.93169&lt;br /&gt;     49950 1006068208 SW       2039.86985&lt;br /&gt;     49950 1026642145 NW       2022.24281&lt;br /&gt;     49950 1025778509 NW       2062.54042&lt;br /&gt;     49950 1025686933 NW       3158.56803&lt;br /&gt;     49950 1022362563 NW       3747.38909&lt;br /&gt;     49950 1006068200 NW       3791.15352&lt;br /&gt;     49950 1022009617 NW       2596.05951&lt;br /&gt;     49950 1020066904 NW       3337.37142&lt;br /&gt;     49950 1006068395 NW       4568.36393&lt;br /&gt;     49952 1006068633 SW       3628.02563&lt;br /&gt;     49952 1006068437 SW        4142.8273&lt;br /&gt;     49952 1006068137 SW       3201.38033&lt;br /&gt;     49952 1002919963 SW        3479.8352&lt;br /&gt;     49952 1008378808 SW       4545.26149&lt;br /&gt;     49952 1002920004 SW       4531.73697&lt;br /&gt;     49952 1008764319 SW       3459.29299&lt;br /&gt;     49952 1006068206 SE       2021.65502&lt;br /&gt;     49952 1022362561 SW         2330.793&lt;br /&gt;     49952 1006067823 SW       2810.31617&lt;br /&gt;     49952 1002919902 SW       3859.54661&lt;br /&gt;     49952 1006068139 SE       2240.00223&lt;br /&gt;     49952 1001235397 SW       1855.94854&lt;br /&gt;     49952 1022009618 SW       1463.18591&lt;br /&gt;     49952 1006068585 SW       2491.16539&lt;br /&gt;     49952 1006068479 SE       1237.73503&lt;br /&gt;     49952 1006068381 SW       3055.63512&lt;br /&gt;     49952 1027708907 SW       3536.07494&lt;br /&gt;     49952 1006067716 SW       2673.85303&lt;br /&gt;     49952 1006068208 SW       558.660004&lt;br /&gt;     49952 1006067854 SW       2193.10054&lt;br /&gt;     49952 1026642145 NW       435.910541&lt;br /&gt;     49952 1025778509 NW       603.927976&lt;br /&gt;     49952 1002919979 NW       2058.37266&lt;br /&gt;     49952 1025686933 NW       1719.64764&lt;br /&gt;     49952 1022362563 NW       2248.00022&lt;br /&gt;     49952 1006068200 NW       2332.77196&lt;br /&gt;     49952 1006068683 NW       3040.36527&lt;br /&gt;     49952 1006067983 NW       3812.09299&lt;br /&gt;     49952 1022009617 NW       1515.13201&lt;br /&gt;     49952 1020066904 NW       2175.32802&lt;br /&gt;&lt;br /&gt;THEN I USE THE ANALYTICAL FUNCTION DENSE_RANK TO ASSIGN A RANKING VALUE FOR &lt;br /&gt;THE DISTANCE BY SECTION NUMBER (RECNMBR) TO EACH WELL&lt;br /&gt;&lt;br /&gt;select recnmbr, kid, quadrant, distance_to_cell,         &lt;br /&gt; dense_rank()&lt;br /&gt;       over (partition by recnmbr order by distance_to_cell  ) TOPN_TOTAL         &lt;br /&gt;from (       &lt;br /&gt;  select a.recnmbr recnmbr, b.kid kid,&lt;br /&gt;    case &lt;br /&gt;    when b.x_coord &lt; a.center_x and b.Y_COORD &lt; a.center_y then 'SW'&lt;br /&gt;    when b.x_coord &lt; a.center_x and b.Y_COORD &gt; a.center_y then 'NW'&lt;br /&gt;    when b.x_coord &gt; a.center_x and b.Y_COORD &lt; a.center_y then 'SE'&lt;br /&gt;    when b.x_coord &gt; a.center_x and b.Y_COORD &gt; a.center_y then 'NE'&lt;br /&gt;     end QUADRANT,&lt;br /&gt;  sqrt( ( (b.x_coord - a.center_x) * (b.x_coord - a.center_x) ) + &lt;br /&gt;      ( (b.Y_COORD - a.center_y) * (b.Y_COORD - a.center_y) ) ) distance_to_cell&lt;br /&gt;    from ACRES640_XYCENTER a, WELLHEADERS_25MAY2004_PRJ b&lt;br /&gt;   where b.y_coord between a.center_y - 3600 and a.center_y + 3600 &lt;br /&gt;     and b.x_coord between a.center_x - 3600  and a.center_x + 3600 &lt;br /&gt;     and a.center_x &gt;= -320688&lt;br /&gt;     and a.center_x &lt;= -284100&lt;br /&gt;     and a.center_y &gt;= 169518&lt;br /&gt;     and a.center_y &lt;= 242855 &lt;br /&gt; )&lt;br /&gt;   &lt;br /&gt;   &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   RECNMBR        KID QU DISTANCE_TO_CELL TOPN_TOTAL&lt;br /&gt;---------- ---------- -- ---------------- ----------   &lt;br /&gt;     49948 1006068139 SW       2280.82989          1&lt;br /&gt;     49948 1006068032 SE       2320.57859          2&lt;br /&gt;     49948 1006068479 SW        3008.3173          3&lt;br /&gt;     49948 1006068206 SW       3434.70581          4&lt;br /&gt;     49948 1006068198 SE       3514.10543          5&lt;br /&gt;     49948 1006067819 NE       4519.37982          6&lt;br /&gt;     49948 1006068137 SW       4533.81749          7&lt;br /&gt;     49948 1006068188 SE       4542.85417          8&lt;br /&gt;     49950 1006068139 SW       1594.49365          1&lt;br /&gt;     49950 1006068479 SW       1646.93169          2&lt;br /&gt;     49950 1026642145 NW       2022.24281          3&lt;br /&gt;     49950 1006068208 SW       2039.86985          4&lt;br /&gt;     49950 1025778509 NW       2062.54042          5&lt;br /&gt;     49950 1006068206 SW       2316.18501          6&lt;br /&gt;     49950 1022009618 SW       2460.49934          7&lt;br /&gt;     49950 1022009617 NW       2596.05951          8&lt;br /&gt;     49950 1001235397 SW       3128.24951          9&lt;br /&gt;     49950 1025686933 NW       3158.56803         10&lt;br /&gt;     49950 1020066904 NW       3337.37142         11&lt;br /&gt;     49950 1022362561 SW       3422.35124         12&lt;br /&gt;     49950 1006068032 SE       3446.22605         13&lt;br /&gt;     49950 1006068137 SW       3580.94959         14&lt;br /&gt;     49950 1022362563 NW       3747.38909         15&lt;br /&gt;     49950 1006068200 NW       3791.15352         16&lt;br /&gt;     49950 1006068633 SW       4129.70144         17&lt;br /&gt;     49950 1002919963 SW       4519.08055         18&lt;br /&gt;     49950 1006068395 NW       4568.36393         19&lt;br /&gt;     49952 1026642145 NW       435.910541          1&lt;br /&gt;     49952 1006068208 SW       558.660004          2&lt;br /&gt;     49952 1025778509 NW       603.927976          3&lt;br /&gt;     49952 1006068479 SE       1237.73503          4&lt;br /&gt;     49952 1022009618 SW       1463.18591          5&lt;br /&gt;     49952 1022009617 NW       1515.13201          6&lt;br /&gt;     49952 1025686933 NW       1719.64764          7&lt;br /&gt;     49952 1001235397 SW       1855.94854          8&lt;br /&gt;     49952 1006068206 SE       2021.65502          9&lt;br /&gt;     49952 1002919979 NW       2058.37266         10&lt;br /&gt;     49952 1020066904 NW       2175.32802         11&lt;br /&gt;     49952 1006067854 SW       2193.10054         12&lt;br /&gt;     49952 1006068139 SE       2240.00223         13&lt;br /&gt;     49952 1022362563 NW       2248.00022         14&lt;br /&gt;     49952 1022362561 SW         2330.793         15&lt;br /&gt;     49952 1006068200 NW       2332.77196         16&lt;br /&gt;     49952 1006068585 SW       2491.16539         17&lt;br /&gt;     49952 1006067716 SW       2673.85303         18&lt;br /&gt;     49952 1006067823 SW       2810.31617         19&lt;br /&gt;     49952 1006068683 NW       3040.36527         20&lt;br /&gt;     49952 1006068381 SW       3055.63512         21&lt;br /&gt;     49952 1006068137 SW       3201.38033         22&lt;br /&gt;     49952 1006068395 NW       3454.67292         23&lt;br /&gt;     49952 1008764319 SW       3459.29299         24&lt;br /&gt;     49952 1002919963 SW        3479.8352         25&lt;br /&gt;     49952 1027708907 SW       3536.07494         26&lt;br /&gt;     49952 1006068633 SW       3628.02563         27&lt;br /&gt;     49952 1006067983 NW       3812.09299         28&lt;br /&gt;     49952 1002919902 SW       3859.54661         29&lt;br /&gt;     49952 1013358575 NW       3955.73204         30&lt;br /&gt;     49952 1006068437 SW        4142.8273         31&lt;br /&gt;     49952 1002920004 SW       4531.73697         32&lt;br /&gt;     49952 1008378808 SW       4545.26149         33   &lt;br /&gt;     &lt;br /&gt;     &lt;br /&gt;NEXT WE SELECT THE 8 CLOSEST WELLS FOR EACH SECTION, WE ALSO NEED TO COMPUTE&lt;br /&gt;THE COUNT OF THE DISTINCT QUADRANTS.  WE NEED THIS BECAUSE SOME INTERPOLATION &lt;br /&gt;TECHNIQUES WORK BETTER IF YOU FORCE THE INTERPOLATED VALUE TO HAVE AT LEAST X &lt;br /&gt;NUMBER OF POINTS IN EACH QUADRANT.  IN THIS CASE WE ARE GOING TO WANT TO HAVE &lt;br /&gt;AT LEAST ONE WELL IN EACH QUADRANT.&lt;br /&gt;&lt;br /&gt;select recnmbr, kid, distance_to_cell, QUADRANT, TOPN_TOTAL, &lt;br /&gt;count(distinct QUADRANT) over (partition by recnmbr) QUAD_COUNT&lt;br /&gt;from (&lt;br /&gt;select recnmbr, kid, distance_to_cell, QUADRANT, TOPN_TOTAL&lt;br /&gt;from (&lt;br /&gt;select recnmbr, kid, quadrant, distance_to_cell,&lt;br /&gt; dense_rank()&lt;br /&gt;       over (partition by recnmbr order by distance_to_cell  ) TOPN_TOTAL         &lt;br /&gt;from (       &lt;br /&gt;  select a.recnmbr recnmbr, b.kid kid,&lt;br /&gt;    case &lt;br /&gt;    when b.x_coord &lt; a.center_x and b.Y_COORD &lt; a.center_y then 'SW'&lt;br /&gt;    when b.x_coord &lt; a.center_x and b.Y_COORD &gt; a.center_y then 'NW'&lt;br /&gt;    when b.x_coord &gt; a.center_x and b.Y_COORD &lt; a.center_y then 'SE'&lt;br /&gt;    when b.x_coord &gt; a.center_x and b.Y_COORD &gt; a.center_y then 'NE'&lt;br /&gt;     end QUADRANT,&lt;br /&gt;  sqrt( ( (b.x_coord - a.center_x) * (b.x_coord - a.center_x) ) + &lt;br /&gt;      ( (b.Y_COORD - a.center_y) * (b.Y_COORD - a.center_y) ) ) distance_to_cell&lt;br /&gt;    from ACRES640_XYCENTER a, WELLHEADERS_25MAY2004_PRJ b&lt;br /&gt;   where b.y_coord between a.center_y - 3600 and a.center_y + 3600 &lt;br /&gt;     and b.x_coord between a.center_x - 3600  and a.center_x + 3600 &lt;br /&gt;     and a.center_x &gt;= -320688&lt;br /&gt;     and a.center_x &lt;= -284100&lt;br /&gt;     and a.center_y &gt;= 169518&lt;br /&gt;     and a.center_y &lt;= 242855 &lt;br /&gt; )&lt;br /&gt;)&lt;br /&gt;where TOPN_TOTAL &lt;= 8&lt;br /&gt;)&lt;br /&gt;        &lt;br /&gt;        &lt;br /&gt;   RECNMBR        KID DISTANCE_TO_CELL QU TOPN_TOTAL QUAD_COUNT&lt;br /&gt;---------- ---------- ---------------- -- ---------- ----------&lt;br /&gt;     49934 1006068645           1800.1 NE          1          3&lt;br /&gt;     49934 1006068218       2281.36122 NE          3          3&lt;br /&gt;     49934 1006068541       3524.63587 NW          6          3&lt;br /&gt;     49934 1006068571        3722.9722 NW          7          3&lt;br /&gt;     49934 1006068190       1808.89607 SW          2          3&lt;br /&gt;     49934 1006068182       2839.38479 SW          4          3&lt;br /&gt;     49934 1006068198       3833.55879 SW          8          3&lt;br /&gt;     49934 1006068545       2948.63036 SW          5          3&lt;br /&gt;     49935 1006068645       513.778162 NE          1          4&lt;br /&gt;     49935 1006079840       4155.58817 NE          7          4&lt;br /&gt;     49935 1006068218       1812.26185 NW          2          4&lt;br /&gt;     49935 1006068541       4270.07283 NW          8          4&lt;br /&gt;     49935 1027709052       3397.06712 SE          3          4&lt;br /&gt;     49935 1023930739       3397.06712 SE          3          4&lt;br /&gt;     49935 1006068190       3402.91713 SW          4          4&lt;br /&gt;     49935 1006068545       3581.14074 SW          5          4&lt;br /&gt;     49935 1006068182       4043.25834 SW          6          4&lt;br /&gt;     49937 1001243091       2834.38124 NE          1          4&lt;br /&gt;     49937 1006344036        3447.8283 NE          6          4&lt;br /&gt;     49937 1006068645       3079.22019 NW          3          4&lt;br /&gt;     49937 1006079840       3140.74704 NW          4          4&lt;br /&gt;     49937 1006068218       3822.73018 NW          8          4&lt;br /&gt;     49937 1006078290       3037.51165 SE          2          4&lt;br /&gt;     49937 1006078651       3798.06859 SE          7          4&lt;br /&gt;     49937 1027709052       3203.50433 SW          5          4&lt;br /&gt;     49937 1023930739       3203.50433 SW          5          4&lt;br /&gt;     49938 1006079840       3328.76974 NE          4          3&lt;br /&gt;     49938 1006344036       4377.68249 NE          7          3&lt;br /&gt;     49938 1001243091       3437.66912 NE          5          3&lt;br /&gt;     49938 1006068645       1535.64091 NW          1          3&lt;br /&gt;     49938 1006068218       2537.84357 NW          2          3&lt;br /&gt;     49938 1027709052       2893.72839 SE          3          3&lt;br /&gt;     49938 1006078290       3944.43317 SE          6          3&lt;br /&gt;     49938 1023930739       2893.72839 SE          3          3        &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;FINALLY WE SELECT ALL SECTIONS THAT HAVE A DISTINCT QUAD COUNT OF 4.  &lt;br /&gt;THE 8 CLOSEST WELLS THAT HAVE AT LEAST ONE WELL IN EACH QUADRANT.&lt;br /&gt;&lt;br /&gt;select recnmbr, kid, distance_to_cell, QUADRANT, TOPN_TOTAL&lt;br /&gt;from (&lt;br /&gt;select recnmbr, kid, distance_to_cell, QUADRANT, TOPN_TOTAL, &lt;br /&gt;count(distinct QUADRANT) over (partition by recnmbr) QUAD_COUNT&lt;br /&gt;from (&lt;br /&gt;select recnmbr, kid, distance_to_cell, QUADRANT, TOPN_TOTAL&lt;br /&gt;from (&lt;br /&gt;  select recnmbr, kid, quadrant, distance_to_cell,&lt;br /&gt;  dense_rank()&lt;br /&gt;        over (partition by recnmbr order by distance_to_cell  ) TOPN_TOTAL         &lt;br /&gt;    from (       &lt;br /&gt;   select a.recnmbr recnmbr, b.kid kid,&lt;br /&gt;     case &lt;br /&gt;     when b.x_coord &lt; a.center_x and b.Y_COORD &lt; a.center_y then 'SW'&lt;br /&gt;     when b.x_coord &lt; a.center_x and b.Y_COORD &gt; a.center_y then 'NW'&lt;br /&gt;     when b.x_coord &gt; a.center_x and b.Y_COORD &lt; a.center_y then 'SE'&lt;br /&gt;     when b.x_coord &gt; a.center_x and b.Y_COORD &gt; a.center_y then 'NE'&lt;br /&gt;      end QUADRANT,&lt;br /&gt;   sqrt( ( (b.x_coord - a.center_x) * (b.x_coord - a.center_x) ) + &lt;br /&gt;       ( (b.Y_COORD - a.center_y) * (b.Y_COORD - a.center_y) ) ) distance_to_cell&lt;br /&gt;     from ACRES640_XYCENTER a, WELLHEADERS_25MAY2004_PRJ b&lt;br /&gt;    where b.y_coord between a.center_y - 3600 and a.center_y + 3600 &lt;br /&gt;      and b.x_coord between a.center_x - 3600  and a.center_x + 3600 &lt;br /&gt;      and a.center_x &gt;= -320688&lt;br /&gt;      and a.center_x &lt;= -284100&lt;br /&gt;      and a.center_y &gt;= 169518&lt;br /&gt;      and a.center_y &lt;= 242855 &lt;br /&gt;  )&lt;br /&gt; )&lt;br /&gt;where TOPN_TOTAL &lt;= 8&lt;br /&gt;)&lt;br /&gt;)&lt;br /&gt;where QUAD_COUNT = 4&lt;br /&gt;&lt;br /&gt;   RECNMBR        KID DISTANCE_TO_CELL QU TOPN_TOTAL                            &lt;br /&gt;---------- ---------- ---------------- -- ----------                            &lt;br /&gt;     49935 1006068645       513.778162 NE          1                            &lt;br /&gt;     49935 1006079840       4155.58817 NE          7                            &lt;br /&gt;     49935 1006068218       1812.26185 NW          2                            &lt;br /&gt;     49935 1006068541       4270.07283 NW          8                            &lt;br /&gt;     49935 1027709052       3397.06712 SE          3                            &lt;br /&gt;     49935 1023930739       3397.06712 SE          3                            &lt;br /&gt;     49935 1006068190       3402.91713 SW          4                            &lt;br /&gt;     49935 1006068545       3581.14074 SW          5                            &lt;br /&gt;     49935 1006068182       4043.25834 SW          6                            &lt;br /&gt;     49937 1001243091       2834.38124 NE          1                            &lt;br /&gt;     49937 1006344036        3447.8283 NE          6                            &lt;br /&gt;     49937 1006068645       3079.22019 NW          3                            &lt;br /&gt;     49937 1006079840       3140.74704 NW          4                            &lt;br /&gt;     49937 1006068218       3822.73018 NW          8                            &lt;br /&gt;     49937 1006078290       3037.51165 SE          2                            &lt;br /&gt;     49937 1006078651       3798.06859 SE          7                            &lt;br /&gt;     49937 1027709052       3203.50433 SW          5                            &lt;br /&gt;     49937 1023930739       3203.50433 SW          5                            &lt;br /&gt;     49942 1006068571        3908.5835 NE          7                            &lt;br /&gt;     49942 1006067819       3588.20693 NW          6                            &lt;br /&gt;     49942 1006068190       1423.03127 SE          1                            &lt;br /&gt;     49942 1006068545       3960.37902 SE          8                            &lt;br /&gt;     49942 1006068182       2597.02849 SE          3                            &lt;br /&gt;     49942 1006068198       1792.30578 SW          2                            &lt;br /&gt;     49942 1006068032       2809.95267 SW          4                            &lt;br /&gt;     49942 1006068188       3394.99411 SW          5                            &lt;br /&gt;     49960 1025686933       1021.17188 NE          3                            &lt;br /&gt;     49960 1025778509       1262.06537 NE          8                            &lt;br /&gt;     49960 1026642145       1187.63041 NE          6                            &lt;br /&gt;     49960 1002919979       575.591869 NW          1                            &lt;br /&gt;     49960 1022362563       1078.89063 NW          4                            &lt;br /&gt;     49960 1006068208       1259.78292 SE          7                            &lt;br /&gt;     49960 1006067854       595.014286 SW          2                            &lt;br /&gt;     49960 1006067716       1167.87414 SW          5                            &lt;br /&gt;     49965 1006068379       573.098595 NE          3                            &lt;br /&gt;     49965 1006067673       1086.42993 NE          6                            &lt;br /&gt;     49965 1022362558       591.472738 NW          4                            &lt;br /&gt;     49965 1026642147       1239.35548 NW          7                            &lt;br /&gt;     49965 1021121940       1074.38029 SE          5                            &lt;br /&gt;     49965 1006068265       1253.18953 SE          8                            &lt;br /&gt;     49965 1002919999        276.06521 SW          1                            &lt;br /&gt;     49965 1025777349       300.026665 SW          2                            &lt;br /&gt;     49966 1006068143       574.381406 NE          5                            &lt;br /&gt;     49966 1006067881       1014.58563 NE          7                            &lt;br /&gt;     49966 1002919986       572.856876 NW          4                            &lt;br /&gt;     49966 1002919921       277.200289 SE          1                            &lt;br /&gt;     49966 1008378793       280.189222 SE          2                            &lt;br /&gt;     49966 1001235373       589.896601 SE          6                            &lt;br /&gt;     49966 1006068265       557.917557 SW          3                            &lt;br /&gt;     49966 1021121940       1121.31396 SW          8                            &lt;br /&gt;     49969 1002919979       1253.72166 NE          8                            &lt;br /&gt;     49969 1022362560       608.152941 NW          3                            &lt;br /&gt;     49969 1006067716       855.977803 SE          4                            &lt;br /&gt;     49969 1006067854       1024.65311 SE          5                            &lt;br /&gt;     49969 1008378866        566.39209 SW          1                            &lt;br /&gt;     49969 1027708907       1095.42777 SW          6                            &lt;br /&gt;     49969 1001235373        1251.9976 SW          7                            &lt;br /&gt;     49969 1027625616       591.959458 SW          2                            &lt;br /&gt;     49979 1006068577       531.497883 NE          3                            &lt;br /&gt;     49979 1006068477        1251.4128 NE          6                            &lt;br /&gt;     49979 1006068591       1255.48755 NW          7                            &lt;br /&gt;     49979 1013358584        614.18564 SE          4                            &lt;br /&gt;     49979 1019411297       1270.18739 SE          8                            &lt;br /&gt;     49979 1006812097       280.189222 SW          1                            &lt;br /&gt;     49979 1006067545       282.242803 SW          2                            &lt;br /&gt;     49979 1006068726       1042.14826 SW          5                            &lt;br /&gt;AND ON AND ON....                        &lt;br /&gt;     68143 1028445209       1044.73585 NE          2                            &lt;br /&gt;     68143 1002950389       1708.98391 NE          5                            &lt;br /&gt;     68143 1006155639       2714.99411 NE          8                            &lt;br /&gt;     68143 1025830097       1073.93203 NE          3                            &lt;br /&gt;     68143 1006154723       574.464968 NW          1                            &lt;br /&gt;     68143 1002950475       2615.97898 SE          7                            &lt;br /&gt;     68143 1006155021       1442.30718 SW          4                            &lt;br /&gt;     68143 1028445211       1994.58467 SW          6                            &lt;br /&gt;     68167 1006155879       1637.48099 NE          5                            &lt;br /&gt;     68167 1001322873       1704.43246 NE          6                            &lt;br /&gt;     68167 1022009791       1951.95722 NW          8                            &lt;br /&gt;     68167 1006154897       1160.19007 SE          1                            &lt;br /&gt;     68167 1002950448       1427.05431 SE          3                            &lt;br /&gt;     68167 1006154895         1501.003 SE          4                            &lt;br /&gt;     68167 1006155257       1385.55873 SW          2                            &lt;br /&gt;     68167 1025830091       1778.85188 SW          7                            &lt;br /&gt;     68184 1006155899       618.684087 NE          2                            &lt;br /&gt;     68184 1006155931       1399.38915 NE          3                            &lt;br /&gt;     68184 1006154883       1695.66329 NE          8                            &lt;br /&gt;     68184 1006154895        1690.6274 NW          6                            &lt;br /&gt;     68184 1004752885       1492.82618 SE          4                            &lt;br /&gt;     68184 1027709638       1693.48664 SE          7                            &lt;br /&gt;     68184 1004752884        13.892444 SW          1                            &lt;br /&gt;     68184 1004752837       1620.26448 SW          5                            &lt;br /&gt;     68187 1006154875       1567.44537 NE          3                            &lt;br /&gt;     68187 1006155899       2200.32952 NE          7                            &lt;br /&gt;     68187 1006154895       101.828287 NW          1                            &lt;br /&gt;     68187 1006155879       1575.13079 NW          4                            &lt;br /&gt;     68187 1001322873       2265.00618 NW          8                            &lt;br /&gt;     68187 1006154897       423.398158 NW          2                            &lt;br /&gt;     68187 1004752884       1595.49271 SE          5                            &lt;br /&gt;     68187 1002950448       1993.30304 SW          6                            &lt;br /&gt;&lt;br /&gt;4396 rows selected.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:25.04&lt;br /&gt;&lt;br /&gt;Execution Plan&lt;br /&gt;----------------------------------------------------------                      &lt;br /&gt;   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1402 Card=2330 Bytes          &lt;br /&gt;          =160770)                                                              &lt;br /&gt;                                                                                &lt;br /&gt;   1    0   VIEW (Cost=1402 Card=2330 Bytes=160770)                             &lt;br /&gt;   2    1     WINDOW (SORT) (Cost=1402 Card=2330 Bytes=130480)                  &lt;br /&gt;   3    2       VIEW (Cost=1329 Card=2330 Bytes=130480)                         &lt;br /&gt;   4    3         WINDOW (SORT PUSHED RANK) (Cost=1329 Card=2330 Bytes          &lt;br /&gt;          =69900)                                                               &lt;br /&gt;                                                                                &lt;br /&gt;   5    4           TABLE ACCESS (BY INDEX ROWID) OF 'WELLHEADERS_25MA          &lt;br /&gt;          Y2004_PRJ' (Cost=2 Card=2 Bytes=32)                                   &lt;br /&gt;                                                                                &lt;br /&gt;   6    5             NESTED LOOPS (Cost=1264 Card=2330 Bytes=69900)            &lt;br /&gt;   7    6               TABLE ACCESS (FULL) OF 'ACRES640_XYCENTER' (Co          &lt;br /&gt;          st=72 Card=993 Bytes=13902)                                           &lt;br /&gt;                                                                                &lt;br /&gt;   8    6               INDEX (RANGE SCAN) OF 'WELLHEADERS_25_MAY2004_          &lt;br /&gt;          LATLONG' (NON-UNIQUE) (Cost=6 Card=1690)                              &lt;br /&gt;                                                                                &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Statistics&lt;br /&gt;----------------------------------------------------------                      &lt;br /&gt;          0  recursive calls                                                    &lt;br /&gt;          4  db block gets                                                      &lt;br /&gt;      65267  consistent gets                                                    &lt;br /&gt;        142  physical reads                                                     &lt;br /&gt;          0  redo size                                                          &lt;br /&gt;     183474  bytes sent via SQL*Net to client                                   &lt;br /&gt;       2326  bytes received via SQL*Net from client                             &lt;br /&gt;        295  SQL*Net roundtrips to/from client                                  &lt;br /&gt;          0  sorts (memory)                                                     &lt;br /&gt;          2  sorts (disk)                                                       &lt;br /&gt;       4396  rows processed                                                     &lt;br /&gt;&lt;br /&gt;SQL&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;THE NEXT STEP WOULD BE ACTUALLY DO THE INTERPOLATION....AVERAGE SOME VALUE WHERE &lt;br /&gt;WELL KID = QUERY FROM ABOVE....&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;Questions/Comments?  &lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;&lt;br /&gt;Jeremy&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15655029-114287459634169789?l=geosql.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geosql.blogspot.com/feeds/114287459634169789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=15655029&amp;postID=114287459634169789' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/114287459634169789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/114287459634169789'/><link rel='alternate' type='text/html' href='http://geosql.blogspot.com/2006/03/sql-interpolation-techniques.html' title='SQL Interpolation Techniques'/><author><name>Jeremy</name><uri>http://www.blogger.com/profile/06135435775056095723</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15655029.post-114170714393612375</id><published>2006-03-06T21:49:00.000-06:00</published><updated>2006-03-06T22:57:14.430-06:00</updated><title type='text'>Summary Statistics</title><content type='html'>One of my most used web pages is a page that summarizes a numeric column for min, max, standard deviation, count, and produces a 10 class equal binned &lt;a href="http://en.wikipedia.org/wiki/Histogram"&gt;histogram&lt;/a&gt;.   One way to do this within Oracle is to execute two queries.   The first query gives us the minimum and maximum value to establish how big our binned histogram buckets need to be.   The second query counts the number of rows that fall within each bucket.&lt;br /&gt;&lt;br /&gt;Take the following interactive &lt;a href="http://hercules.kgs.ku.edu/kgs/oilgas/strat_welltops/top_viewer.cfm"&gt;map&lt;/a&gt; from the Kansas Well Top Stratigraphy Viewer:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/chase.1.png"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/chase.0.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The map above is displaying the depth of the Chase formation wells in Kansas relative to sea level.  The statistical summary of that dataset can be viewed by selecting the "View Current Viewing Stats" link.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/chase_stats.png"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/chase_stats.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The first query gives us the min, max, standard deviation, and count.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SELECT avg(WELL_TOP_SEALEVEL) average,&lt;br /&gt;     min(WELL_TOP_SEALEVEL) minimum,&lt;br /&gt;     max(WELL_TOP_SEALEVEL) maximum,&lt;br /&gt;     stddev(WELL_TOP_SEALEVEL) standard_dev,&lt;br /&gt;     count(WELL_TOP_SEALEVEL) count&lt;br /&gt;FROM PLSS.strat_well_top_1MAR2006&lt;br /&gt;WHERE FORMATION_NAME = 'Chase Group'&lt;br /&gt; and WELL_TOP is not null&lt;br /&gt; and WELL_TOP &lt;&gt; 9999&lt;br /&gt; and GROUND_ELEVATION &gt; 0&lt;br /&gt; and LONGITUDE &gt;= -102.25798&lt;br /&gt; and LONGITUDE &lt;= -94.201246      and LATITUDE &gt;= 34.4665145&lt;br /&gt; and LATITUDE &lt;= 42.5232570&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;All we are really doing is letting the database summarize (avg, min, max, etc.) a numeric column (WELL_TOP_SEALEVEL) based on the where criteria (the formation is Chase Group, the well value exists, the well ground elevation is above 0, and the well is within the current viewing extent).&lt;br /&gt;&lt;br /&gt;Once we know the min and max value we can produce a query that counts the number of rows that fall within an equal 10 class range.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SELECT avg(WELL_TOP_SEALEVEL) average,&lt;br /&gt;      stddev(WELL_TOP_SEALEVEL) stddevvalue, '1' C0&lt;br /&gt;,sum(case&lt;br /&gt;     when WELL_TOP_SEALEVEL between -643 AND -410.7&lt;br /&gt;     then 1&lt;br /&gt;     else 0&lt;br /&gt;     end) C1&lt;br /&gt;,sum(case&lt;br /&gt;     when WELL_TOP_SEALEVEL between -410.7 AND -178.4&lt;br /&gt;     then 1&lt;br /&gt;     else 0&lt;br /&gt;     end) C2&lt;br /&gt;,sum(case&lt;br /&gt;     when WELL_TOP_SEALEVEL between -178.4 AND 53.9&lt;br /&gt;     then 1&lt;br /&gt;     else 0&lt;br /&gt;     end) C3&lt;br /&gt;,sum(case&lt;br /&gt;     when WELL_TOP_SEALEVEL between 53.9 AND 286.2&lt;br /&gt;     then 1&lt;br /&gt;     else 0&lt;br /&gt;     end) C4&lt;br /&gt;,sum(case&lt;br /&gt;     when WELL_TOP_SEALEVEL between 286.2 AND 518.5&lt;br /&gt;     then 1&lt;br /&gt;     else 0&lt;br /&gt;     end) C5&lt;br /&gt;,sum(case&lt;br /&gt;     when WELL_TOP_SEALEVEL between 518.5 AND 750.8&lt;br /&gt;     then 1&lt;br /&gt;     else 0&lt;br /&gt;     end) C6&lt;br /&gt;,sum(case&lt;br /&gt;     when WELL_TOP_SEALEVEL between 750.8 AND 983.1&lt;br /&gt;     then 1&lt;br /&gt;     else 0&lt;br /&gt;     end) C7&lt;br /&gt;,sum(case&lt;br /&gt;     when WELL_TOP_SEALEVEL between 983.1 AND 1215.4&lt;br /&gt;     then 1&lt;br /&gt;     else 0&lt;br /&gt;     end) C8&lt;br /&gt;,sum(case&lt;br /&gt;     when WELL_TOP_SEALEVEL between 1215.4 AND 1447.7&lt;br /&gt;     then 1&lt;br /&gt;     else 0&lt;br /&gt;     end) C9&lt;br /&gt;,sum(case&lt;br /&gt;     when WELL_TOP_SEALEVEL between 1447.7 AND 1680&lt;br /&gt;     then 1&lt;br /&gt;     else 0&lt;br /&gt;     end) C10&lt;br /&gt; FROM PLSS.strat_well_top_1MAR2006&lt;br /&gt;WHERE FORMATION_NAME = 'Chase Group'&lt;br /&gt;  AND WELL_TOP is not null&lt;br /&gt;  AND WELL_TOP &lt;&gt; 9999&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here we are using the case function on a row by row basis. &lt;br /&gt;&lt;b&gt;&lt;pre&gt;&lt;br /&gt;sum(case    &lt;br /&gt;     when WELL_TOP_SEALEVEL between 1447.7 AND 1680&lt;br /&gt;     then 1&lt;br /&gt;     else 0&lt;br /&gt;   end)&lt;br /&gt;&lt;/pre&gt;&lt;/b&gt;&lt;br /&gt;If the value is between x and y then give it a value of 1, otherwise give it a value of 0.  When we sum up that count for all rows we end up with a number of rows where the value is within the pre-defined bin.&lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;&lt;br /&gt;Jeremy&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15655029-114170714393612375?l=geosql.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geosql.blogspot.com/feeds/114170714393612375/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=15655029&amp;postID=114170714393612375' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/114170714393612375'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/114170714393612375'/><link rel='alternate' type='text/html' href='http://geosql.blogspot.com/2006/03/summary-statistics.html' title='Summary Statistics'/><author><name>Jeremy</name><uri>http://www.blogger.com/profile/06135435775056095723</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15655029.post-113924636673796925</id><published>2006-02-06T10:14:00.000-06:00</published><updated>2006-03-06T21:47:45.166-06:00</updated><title type='text'>The Power of the Spatial to Attribute Join-Part 3</title><content type='html'>Sorry for the long delay between posts!&lt;br /&gt;&lt;br /&gt;Today we are going to look at multi-dimensional subsurface mapping.  First a little background.  The &lt;a href="http://www.kgs.ku.edu"&gt;Kansas Geological Survey&lt;/a&gt; has an extensive database of subsurface tops. A geologic top is the depth in feet from the surface to a particular geologic unit (system, group, formation, member). This data is collected from numerous scientists working over many years. When a well is drilled (mostly for petroleum) geophysical logs are run in the hole to measure different properties of the rocks. These electric logs are scanned, studied, and geologic units are picked from the logs (Chase group, Permian system, Fort Scott limestone formation). Read this &lt;a href="http://www.kgs.ku.edu/Publications/Oil/primer07.html"&gt;primer&lt;/a&gt; for more information.&lt;br /&gt;&lt;br /&gt;So what does this mean for GIS and SQL? With this database we have access to over 1,700,000 called tops spread across ~150,000 wells in the state of Kansas. Each well can/will have more than one called formation. We have more than one record per geographic location--in this case the records represent mulitple entries (formations) in the z domain.&lt;br /&gt;&lt;br /&gt;We can visualize some of this dataset in ArcScene (or any other 3D package).&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://hercules.kgs.ku.edu/kgs/oilgas/powerpoints/chase_top_3d_small.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 500px;" src="http://hercules.kgs.ku.edu/kgs/oilgas/powerpoints/chase_top_3d_smaller.PNG" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Most analysis and visualization occurs when users map one unit of measure (depth to unit, thickness between units, or something else entirely) per geographic location.&lt;br /&gt;&lt;br /&gt;The query to select an individual unit is pretty easy.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;SQL&amp;gt; desc strat_well_top_1JUN2005&lt;br /&gt;Name                              Null?    Type&lt;br /&gt;--------------------------------- -------- ------------------------&lt;br /&gt;FORMATION_NAME                    NOT NULL VARCHAR2(60)&lt;br /&gt;WELL_HEADER_KID                   NOT NULL NUMBER(10)&lt;br /&gt;WELL_TOP                                   NUMBER(8,2)&lt;br /&gt;FIELD_KID                                  NUMBER(10)&lt;br /&gt;LATITUDE                                   NUMBER(11,6)&lt;br /&gt;LONGITUDE                                  NUMBER(11,6)&lt;br /&gt;GROUND_ELEVATION                           VARCHAR2(40)&lt;br /&gt;GROUND_ELEVATION_SOURCE                    VARCHAR2(12)&lt;br /&gt;WELL_TOP_SEALEVEL_NON_NED                  VARCHAR2(40)&lt;br /&gt;WELL_TOP_SEALEVEL                          NUMBER&lt;br /&gt;&lt;br /&gt;1  select well_header_kid, latitude, longitude,&lt;br /&gt;2         well_top, well_top_sealevel&lt;br /&gt;3  from strat_well_top_1JUN2005&lt;br /&gt;4* where FORMATION_NAME = 'Permian System'&lt;br /&gt;SQL&amp;gt; /&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;WELL_HEADER_KID   LATITUDE  LONGITUDE   WELL_TOP WELL_TOP_SEALEVEL&lt;br /&gt;--------------- ---------- ---------- ---------- -----------------&lt;br /&gt;1025687130   37.58751 -101.36115        680             -2381&lt;br /&gt;1028094976   37.61659 -100.73941        834             -2095&lt;br /&gt;1006155619   37.39194 -101.67532        608             -2673&lt;br /&gt;1006514758   39.99071  -97.14744        358             -1158&lt;br /&gt;1025773538   37.20899 -101.90656       1395             -2120&lt;br /&gt;1024492073   37.00136 -100.56991       3550              1170&lt;br /&gt;1026599879   37.91949 -101.48087        660             -2529&lt;br /&gt;1006054521   37.50601  -99.70401        387             -2066&lt;br /&gt;1006054213   37.53783   -99.8804        417             -2098&lt;br /&gt;1006054635   37.48215 -100.02145        412             -2179&lt;br /&gt;1002915548   37.55853 -100.38357        775             -2008&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This can be done easily outside of database. With ArcMap you can do a definition query to limit the tabluar dataset to only the unit in question. &lt;br /&gt;&lt;br&gt;With ArcIMS you can perform an ArcXML spatial query to only select the unit in question.&lt;br /&gt;&lt;pre&gt;&amp;lt;LAYER type=&amp;quot;featureclass&amp;quot; name=&amp;quot;Depth&amp;quot; visible=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;DATASET fromlayer=&amp;quot;1&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;SPATIALQUERY searchorder=&amp;quot;attributefirst&amp;quot;&lt;br /&gt;where=&amp;quot;PLSS.WELL_HEADERS_29AUG2003.KID = PLSS.STRAT_WELL_TOP_28AUG2003.WELL_HEADER_KID&lt;br /&gt;and PLSS.STRAT_WELL_TOP_28AUG2003.FORMATION_NAME = 'Permian System'&lt;br /&gt;and PLSS.STRAT_WELL_TOP_28AUG2003.WELL_TOP &amp;lt;&amp;gt; 9999&lt;br /&gt;and PLSS.STRAT_WELL_TOP_28AUG2003.GROUND_ELEVATION &amp;gt; 0&amp;quot;&lt;br /&gt;jointables=&amp;quot;PLSS.STRAT_WELL_TOP_28AUG2003&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;VALUEMAPRENDERER lookupfield=&amp;quot;PLSS.STRAT_WELL_TOP_28AUG2003.WELL_TOP&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;RANGE lower=&amp;quot;15&amp;quot; upper=&amp;quot;326&amp;quot; label=&amp;quot;15 TO 326&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;SIMPLEMARKERSYMBOL color=&amp;quot;56,168,0&amp;quot; width=&amp;quot;6&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/RANGE&amp;gt;&lt;br /&gt;&amp;lt;RANGE lower=&amp;quot;326&amp;quot; upper=&amp;quot;637&amp;quot; label=&amp;quot;326 TO 637&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;SIMPLEMARKERSYMBOL color=&amp;quot;90,186,0&amp;quot; width=&amp;quot;6&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/RANGE&amp;gt;&lt;br /&gt;&amp;lt;RANGE lower=&amp;quot;637&amp;quot; upper=&amp;quot;949&amp;quot; label=&amp;quot;637 TO 949&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;SIMPLEMARKERSYMBOL color=&amp;quot;131,207,0&amp;quot; width=&amp;quot;6&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/RANGE&amp;gt;&lt;br /&gt;&amp;lt;RANGE lower=&amp;quot;949&amp;quot; upper=&amp;quot;1260&amp;quot; label=&amp;quot;949 TO 1260&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;SIMPLEMARKERSYMBOL color=&amp;quot;176,224,0&amp;quot; width=&amp;quot;6&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/RANGE&amp;gt;&lt;br /&gt;&amp;lt;RANGE lower=&amp;quot;1260&amp;quot; upper=&amp;quot;1571&amp;quot; label=&amp;quot;1260 TO 1571&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;SIMPLEMARKERSYMBOL color=&amp;quot;228,245,0&amp;quot; width=&amp;quot;6&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/RANGE&amp;gt;&lt;br /&gt;&amp;lt;RANGE lower=&amp;quot;1571&amp;quot; upper=&amp;quot;1882&amp;quot; label=&amp;quot;1571 TO 1882&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;SIMPLEMARKERSYMBOL color=&amp;quot;255,225,0&amp;quot; width=&amp;quot;6&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/RANGE&amp;gt;&lt;br /&gt;&amp;lt;RANGE lower=&amp;quot;1882&amp;quot; upper=&amp;quot;2193&amp;quot; label=&amp;quot;1882 TO 2193&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;SIMPLEMARKERSYMBOL color=&amp;quot;255,170,0&amp;quot; width=&amp;quot;6&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/RANGE&amp;gt;&lt;br /&gt;&amp;lt;RANGE lower=&amp;quot;2193&amp;quot; upper=&amp;quot;2504&amp;quot; label=&amp;quot;2193 TO 2504&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;SIMPLEMARKERSYMBOL color=&amp;quot;255,115,0&amp;quot; width=&amp;quot;6&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/RANGE&amp;gt;&lt;br /&gt;&amp;lt;RANGE lower=&amp;quot;2504&amp;quot; upper=&amp;quot;2816&amp;quot; label=&amp;quot;2504 TO 2816&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;SIMPLEMARKERSYMBOL color=&amp;quot;255,55,0&amp;quot; width=&amp;quot;6&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/RANGE&amp;gt;&lt;br /&gt;&amp;lt;RANGE lower=&amp;quot;2816&amp;quot; upper=&amp;quot;3550&amp;quot; label=&amp;quot;2816 TO 3550&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;SIMPLEMARKERSYMBOL color=&amp;quot;255,0,0&amp;quot; width=&amp;quot;6&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;/RANGE&amp;gt;&lt;br /&gt;&amp;lt;/VALUEMAPRENDERER&amp;gt;&lt;br /&gt;&amp;lt;/LAYER&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This looks like....&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://hercules.kgs.ku.edu/kgs/oilgas/powerpoints/permian_tops.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 500px;" src="http://hercules.kgs.ku.edu/kgs/oilgas/powerpoints/permian_tops.PNG" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Lets get a little more complicated. Say you want to compute the thickness between two different formations. One way to do this is to select the two formations of interest, group the results, and select the difference between the min depth value and the max depth value.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;select WELL_HEADER_KID, round(max(WELL_TOP) - min(WELL_TOP),1) STRAT_THICKNESS&lt;br /&gt;from strat_well_top_1JUN2005&lt;br /&gt;where (formation_name = 'Chase Group'&lt;br /&gt;or formation_name = 'Council Grove Group')&lt;br /&gt;and WELL_TOP is not null&lt;br /&gt;and WELL_TOP &amp;lt;&amp;gt; 9999&lt;br /&gt;and LONGITUDE &amp;gt;= -103.57371&lt;br /&gt;and LONGITUDE &amp;lt;= -98.352965    &lt;br /&gt;and LATITUDE &amp;gt;= 34.9908216&lt;br /&gt;and LATITUDE &amp;lt;= 40.2115692 &lt;br /&gt;group by WELL_HEADER_KID &lt;br /&gt;having count(distinct formation_name) = 2&lt;br /&gt;and max(WELL_TOP) - min(WELL_TOP) &amp;gt; 0&lt;br /&gt;and max(WELL_TOP) - min(WELL_TOP) &amp;lt;&amp;gt; max(WELL_TOP)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;By selecting only the Chase Group and the Council Grove Group we lower our tops table to records that have either the Chase or The Council Grove. Once we group by the well_header_kid and select records that have rows in both groups we can do the math to compute the thickness.&lt;br /&gt;&lt;pre&gt;group by WELL_HEADER_KID &lt;br /&gt; having count(distinct formation_name) = 2 &lt;/pre&gt;&lt;br /&gt;This drops records of wells that have one group or the other, but not both.&lt;br /&gt;&lt;br /&gt;Now we can subtract the &amp;quot;min(well_top)&amp;quot; depth from the &amp;quot;max(well_top)&amp;quot; depth to compute the thickness between the two groups for a particluar well.&lt;br /&gt;&lt;br /&gt;Slap that query to a view and join that in ArcIMS and you have nice point map of the thickness between two geologic groups.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://hercules.kgs.ku.edu/kgs/oilgas/powerpoints/chase_council_thickness.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 500px;" src="http://hercules.kgs.ku.edu/kgs/oilgas/powerpoints/chase_council_thickness.PNG" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Give it a try at:  &lt;a href="http://hercules.kgs.ku.edu/kgs/oilgas/strat_welltops/top_viewer.cfm"&gt;http://hercules.kgs.ku.edu/kgs/oilgas/strat_welltops/top_viewer.cfm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Or we can use ArcGIS server to generate a raster dataset off that that view (example application coming soon).&lt;br /&gt;&lt;br /&gt;What do you think?&lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;&lt;br /&gt;Jeremy&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15655029-113924636673796925?l=geosql.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geosql.blogspot.com/feeds/113924636673796925/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=15655029&amp;postID=113924636673796925' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/113924636673796925'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/113924636673796925'/><link rel='alternate' type='text/html' href='http://geosql.blogspot.com/2006/02/power-of-spatial-to-attribute-join.html' title='The Power of the Spatial to Attribute Join-Part 3'/><author><name>Jeremy</name><uri>http://www.blogger.com/profile/06135435775056095723</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15655029.post-113168291182752649</id><published>2005-11-10T21:49:00.000-06:00</published><updated>2005-11-10T22:25:00.936-06:00</updated><title type='text'>The Power of the Spatial to Attribute Join-Part 2</title><content type='html'>This is part two on my series on the mapping and analysis of complex multi-dimensional datasets. Today we will look at historical sea surface temperatures (SST). I am by no means an expert on SST models our on the effect of warming sea surface temperatures on oceanic biological habitat. So take this example with a grain of salt...&lt;br /&gt;&lt;br /&gt;IMPORTANCE: The number of consecutive records above the max baseline can adversely effect the benthic habitat of the oceanic environment. For example, El Nino can cause coral reef bleaching. This bleaching occurs because sea surface temperatures are continuously above the historical upper limit for the species.&lt;br /&gt;&lt;br /&gt;GOAL: For every unique ID_ONEDG (unique spatial location), select the maximum number of CONSECUTIVE months that are above the long term average maximum yearly value.&lt;br /&gt;&lt;br /&gt;EXAMPLE DATASET:  HADL_SST&lt;br /&gt;TABLE COMMENTS: Sea Surface Temperatures: OI version 2 SST Analysis from NCEP - Reynolds, Smith, and Stokes. One degree resolution. Monthly from 1871 to 1999. Extent: 40N Latitude to 40S Latitude No land. Modeled data.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SQL&gt; desc hadl_sst&lt;br /&gt;Name                                      Null?    Type&lt;br /&gt;----------------------------------------- -------- ------------&lt;br /&gt;ID_ONEDG                                  NOT NULL NUMBER(6)&lt;br /&gt;DATE_RECORDED                             NOT NULL DATE&lt;br /&gt;SST_CENTIGRADE                            NOT NULL NUMBER(6,2)   &lt;br /&gt;      &lt;br /&gt;Total number of records:  33676740&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For speed purposes, for this example, we need to compute the max_baseline_value.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;create table HADL_SST_AVG_YR_MAX_MNTH as (&lt;br /&gt;select ID_ONEDG, avg(yearly_max) MAX_BASELINE_VALUE&lt;br /&gt;from (select ID_ONEDG, max(SST_CENTIGRADE) yearly_max&lt;br /&gt;     from hadl_sst&lt;br /&gt;    group by ID_ONEDG, to_char(DATE_RECORDED, 'YYYY')&lt;br /&gt;  )&lt;br /&gt;group by ID_ONEDG&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;SQL&gt; desc HADL_SST_AVG_YR_MAX_MNTH&lt;br /&gt;Name                                      Null?    Type&lt;br /&gt;----------------------------------------- -------- ---------------------&lt;br /&gt;ID_ONEDG                                  NOT NULL NUMBER(6)&lt;br /&gt;MAX_BASELINE_VALUE                                 NUMBER&lt;br /&gt;&lt;br /&gt;Total number of records:  21755&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Spatial attribute table that contains spatial information about the center of the one degree cell (latitude and longitude). This is a table that is registered with ESRI's spatial database engine (SDE). This can be visualized with traditional GIS software.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SQL&gt; desc one_degree&lt;br /&gt;Name                                      Null?    Type&lt;br /&gt;----------------------------------------- -------- --------------------&lt;br /&gt;OBJECTID                                  NOT NULL NUMBER(38)&lt;br /&gt;LONG_1                                             NUMBER(6,1)&lt;br /&gt;LAT_1                                              NUMBER(6,1)&lt;br /&gt;ID_ONEDG                                           NUMBER(6)&lt;br /&gt;SHAPE                                              NUMBER(38)&lt;br /&gt;&lt;br /&gt;Total number of records:  64800&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The objectives of my approach to this query are:&lt;br /&gt;-Select all records that have a monthly temperature greater than the baseline over a predefined three year period centered on an elnino year (or la nina).&lt;br /&gt;-Group the selected rows for each ID_ONEDG where the previous record is within a month AND has a temperature value greater than the baseline.&lt;br /&gt;&lt;br /&gt;This is where we take advantage of the LAG/LEAD Analytical function provided by Oracle.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;select A.ID_ONEDG ID_ONEDG,&lt;br /&gt;  a.date_recorded date_recorded,&lt;br /&gt;  case&lt;br /&gt;  when date_recorded -&lt;br /&gt;       lag(a.date_recorded)&lt;br /&gt;          over (order by a.ID_ONEDG,  a.date_recorded)&lt;br /&gt;       not between 0 and 35&lt;br /&gt;  then rownum&lt;br /&gt;end rn,&lt;br /&gt;  a.sst_centigrade sst_centigrade,&lt;br /&gt;  b.MAX_BASELINE_VALUE MAX_BASELINE_VALUE&lt;br /&gt;from hadl_sst a, HADL_SST_AVG_YR_MAX_MNTH B, ONE_DEGREE C&lt;br /&gt;where C.LAT_1 between -40 and 40&lt;br /&gt;and B.ID_ONEDG = C.ID_ONEDG&lt;br /&gt;and A.ID_ONEDG = B.ID_ONEDG&lt;br /&gt;and A.date_recorded between&lt;br /&gt;  to_date('01-jan-1957', 'dd-mon-yyyy')&lt;br /&gt;  and to_date('31-dec-1959', 'dd-mon-yyyy')&lt;br /&gt;and a.sst_centigrade &gt; b.MAX_BASELINE_VALUE&lt;br /&gt;order by a.ID_ONEDG,  a.date_recorded&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ID_ONEDG DATE_RECO         RN SST_CENTIGRADE MAX_BASELINE_VALUE&lt;br /&gt;---------- --------- ---------- -------------- ------------------&lt;br /&gt; 18041 01-AUG-98         35          20.47         20.1232558&lt;br /&gt; 18042 01-AUG-98                     20.66         19.9818605&lt;br /&gt; 18043 01-AUG-98                      20.7         19.8624806&lt;br /&gt; 18044 01-AUG-98                     20.56         19.6863566&lt;br /&gt; 18044 01-SEP-98                     19.87         19.6863566&lt;br /&gt; 18045 01-AUG-97         40          19.63          19.465969&lt;br /&gt; 18045 01-SEP-97                     19.58          19.465969&lt;br /&gt; 18045 01-AUG-98         42          20.26          19.465969&lt;br /&gt; 18045 01-SEP-98                     19.91          19.465969&lt;br /&gt; 18046 01-AUG-97         44          19.72         19.2837209&lt;br /&gt; 18046 01-SEP-97                     19.65         19.2837209&lt;br /&gt; 18046 01-AUG-98         46          20.05         19.2837209&lt;br /&gt; 18046 01-SEP-98                     19.87         19.2837209&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice that ID_ONEDG of 18045 has two groups of consecutive months where the temperature is greater than the baseline value (Aug-97 to Sep-97 &amp; Aug-98 to Sep-98).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;-Once the groups have been recognized we need to carry the group id forward.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;select ID_ONEDG,&lt;br /&gt;  nvl(max(rn)&lt;br /&gt;      over (order by ID_ONEDG,date_recorded),&lt;br /&gt;   -1) max_rn&lt;br /&gt;from ( QUERY-FROM-ABOVE )&lt;br /&gt;order by 1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ID_ONEDG     MAX_RN&lt;br /&gt;---------- ----------&lt;br /&gt;18041         35&lt;br /&gt;18042         35&lt;br /&gt;18043         35&lt;br /&gt;18044         35&lt;br /&gt;18044         35&lt;br /&gt;18045         40&lt;br /&gt;18045         40&lt;br /&gt;18045         42&lt;br /&gt;18045         42&lt;br /&gt;18046         44&lt;br /&gt;18046         44&lt;br /&gt;18046         46&lt;br /&gt;18046         46&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice that for ID_ONEDG of 18045 we have two groups each with two values (40 and 42).&lt;br /&gt;&lt;br /&gt;-Now we group id_onedg and the max_rn to compute the count of records that have similar values for id_onedg and max_rn.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;select ID_ONEDG, count(max_rn) consec_months&lt;br /&gt;from ( QUERY-FROM-ABOVE )&lt;br /&gt;group by ID_ONEDG, max_rn&lt;br /&gt;&lt;br /&gt;ID_ONEDG CONSEC_MONTHS&lt;br /&gt;---------- -------------&lt;br /&gt;18041             1&lt;br /&gt;18042             1&lt;br /&gt;18043             1&lt;br /&gt;18044             2&lt;br /&gt;18045             2&lt;br /&gt;18045             2&lt;br /&gt;18046             2&lt;br /&gt;18046             2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;-Now that we have the count for all consecutive months above the baseline for each id_onedg we need to select the maximum number of consecutive months.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;select max(consec_months) max_consecutive, ID_ONEDG&lt;br /&gt;from ( QUERY-FROM-ABOVE )&lt;br /&gt;group by ID_ONEDG&lt;br /&gt;&lt;br /&gt;MAX_CONSECUTIVE   ID_ONEDG&lt;br /&gt;--------------- ----------&lt;br /&gt;         1      18041&lt;br /&gt;         1      18042&lt;br /&gt;         1      18043&lt;br /&gt;         2      18044&lt;br /&gt;         2      18045&lt;br /&gt;         2      18046&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;WRAP-UP: Analytical functions can be very powerful. The only way to do the previous query without analytical functions would be to build a PL/SQL procedure (email me if you want to see that version) that does the max consecutive computation for each spatial location.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;select max(consec_months) max_consecutive, ID_ONEDG&lt;br /&gt; from&lt;br /&gt;    (&lt;br /&gt;     select ID_ONEDG, count(max_rn) consec_months&lt;br /&gt;       from&lt;br /&gt;          (&lt;br /&gt;           select ID_ONEDG, nvl(max(rn)&lt;br /&gt;                            over(order by ID_ONEDG,date_recorded), -1) max_rn&lt;br /&gt;             from&lt;br /&gt;                (&lt;br /&gt; select A.ID_ONEDG ID_ONEDG,&lt;br /&gt;        a.date_recorded date_recorded,&lt;br /&gt;        case&lt;br /&gt;               when date_recorded - lag(a.date_recorded) over (order by a.ID_ONEDG,  a.date_recorded) not between 0 and 35&lt;br /&gt;        then rownum&lt;br /&gt;         end rn,&lt;br /&gt;        a.sst_centigrade sst_centigrade,&lt;br /&gt;        b.MAX_BASELINE_VALUE MAX_BASELINE_VALUE&lt;br /&gt;   from hadl_sst a, HADL_SST_AVG_YR_MAX_MNTH B, ONE_DEGREE C&lt;br /&gt;  where C.LAT_1 between -40 and 40&lt;br /&gt;    and B.ID_ONEDG = C.ID_ONEDG&lt;br /&gt;    and A.ID_ONEDG = B.ID_ONEDG&lt;br /&gt;    and A.date_recorded between to_date('01-jan-1997', 'dd-mon-yyyy') and to_date('31-dec-1999', 'dd-mon-yyyy')&lt;br /&gt;    and a.sst_centigrade &gt; b.MAX_BASELINE_VALUE&lt;br /&gt;  order by a.ID_ONEDG,  a.date_recorded&lt;br /&gt;                )&lt;br /&gt;            order by 1   &lt;br /&gt;          )&lt;br /&gt;       group by ID_ONEDG, max_rn&lt;br /&gt;    )&lt;br /&gt;group by ID_ONEDG&lt;br /&gt;&lt;br /&gt;21516 rows selected.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:24.06&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;So what does it look like?&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/analysis80_83.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/analysis80_83.png" alt="" border="0" /&gt;&lt;/a&gt;Conesecutive months above the baseline maximum sea surface temperature for the three year period of 1979 to 1981 (1980 was considered a normal year) and the three year period of 1982 to 1984 (1984 was considered a El Nino period).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/analysis89_97.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/analysis89_97.png" alt="" border="0" /&gt;&lt;/a&gt;Conesecutive months above the baseline maximum sea surface temperature for the three year period of 1988 to 1990 (1989 was considered a La Nina year) and the three year period of 1996 to 1998 (1997 was considered a strong El Nino period).&lt;br /&gt;&lt;br /&gt;Questions?  Comments?&lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;&lt;br /&gt;Jeremy&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15655029-113168291182752649?l=geosql.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geosql.blogspot.com/feeds/113168291182752649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=15655029&amp;postID=113168291182752649' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/113168291182752649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/113168291182752649'/><link rel='alternate' type='text/html' href='http://geosql.blogspot.com/2005/11/power-of-spatial-to-attribute-join_10.html' title='The Power of the Spatial to Attribute Join-Part 2'/><author><name>Jeremy</name><uri>http://www.blogger.com/profile/06135435775056095723</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15655029.post-113021112721196985</id><published>2005-11-01T10:00:00.000-06:00</published><updated>2005-11-02T08:22:49.550-06:00</updated><title type='text'>The Power of the Spatial to Attribute Join-Part 1</title><content type='html'>This is the start of a series of posts related to the mapping and analysis of complex multi-dimensional datasets. Traditionally it has been difficult to map multiple dimensional datasets in a GIS. In this series we are going to look at several database driven GIS projects related to multi-dimensional mapping.&lt;br /&gt;&lt;br /&gt;The first project relates to the mapping and analysis of Kansas Oil and Gas production data.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://hercules.kgs.ku.edu/kgs/oilgas/production/imageviewertest.cfm"&gt;Oil and Gas Production Through Time&lt;/a&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt; A dynamic web page that allows a user to map production data by section through time. For each product (oil or gas), you can map production by year, range of years (average or cumulative), or the percent change from one year to another. This is a good example of time-series gis within an enterprise database system.&lt;br /&gt;&lt;/span&gt;From...  &lt;a href="http://www.kgs.ku.edu/PRS/petroMaps.html"&gt;KGS Energy Resources Interactive Maps&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/leases_production_diagram1.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/leases_production_diagram1.jpg" alt="" border="0"&gt;&lt;/a&gt;The image to the right contains a table schematic of the main lease table in our database. This table identifies how much oil and gas was produced from a designated lease. As you can see we have:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;time--year and month columns&lt;/li&gt;   &lt;li&gt;product--oil or gas&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;production--amount produced during a particular time, at a particular area, for a particular product  &lt;/li&gt;   &lt;li&gt;lease lactation reference--location or locations of the wells or leases&lt;/li&gt; &lt;/ul&gt; While this is useful information we need to structure it a bit more to make useful real-time mapping visualization. Because of the complex nature of lease information, we cannot currently match leases to particular wells in Kansas. We can aggregate the spatial location of leases up to public land survey boundaries (PLSS). Once we do this aggregation we have a much cleaner table to work with.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/acres_640_diagram.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/320/acres_640_diagram.jpg" alt="" border="0"&gt;&lt;/a&gt;&lt;br /&gt;Where &amp;quot;RECNMBR&amp;quot; is the unique id for a particular 640-acre section in Kansas.&lt;br /&gt;&lt;br /&gt;From this table can construct queries that identify the amount of production for a particular product for a particular year or for the sum over a range of years.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/oil-gas-view-1990-20001.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/oil-gas-view-1990-20001.jpg" alt="" border="0"&gt;&lt;/a&gt;&lt;br /&gt;In the query above we are asking the database to create a view that gives us the sum of gas production between from 1990 to 2000. Within this view we are using the Group By function to group the recnmbr column into a distinct number. Each distinct recnmbr will have multiple production values. First we eliminate all the rows that do not produce gas (where product = 'G') and then we eliminate all the rows where the year is not between 1990 and 2000. We are then left with rows that have produced gas between 1990 and 2000. Take RECNMBR 2555, it has produced gas 10 out of the 12 possible years in that range. We need to summarize these 10 values for this unique RECNMBR. We can perform functions like: count, average, min, max, and sum. In our case we are going to sum the values that fit our criteria.&lt;br /&gt;&lt;br /&gt;Now we have reduced that multi-dimensional table to one value per spatial polygon (RECNMBR). We can now join that view to a spatial dataset in either ArcMap or ArcIMS. Now we can easily produce a map like this...&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/production_gas_1990-2000.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/production_gas_1990-2000.jpg" alt="" border="0"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Let's take it a step further and say we want to produce a map of the percent change in gas production between the years 1990 and 2000. To do that we need to formulate a bit more complicated query.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;CREATE OR REPLACE VIEW OIL_GAS_WEB_PROD163922 AS&lt;br /&gt;(select a.recnmbr as RECNMBR,&lt;br /&gt;    decode(sign(avg(b.x1)-avg(c.x2)),&lt;br /&gt;           1, ROUND((-100 * (avg(b.x1) - avg(c.x2))/avg(b.x1)),0),&lt;br /&gt;           -1,ROUND((-100 * (avg(b.x1) - avg(c.x2))/avg(b.x1)),0),&lt;br /&gt;           0) as PERCENTCHANGE&lt;br /&gt;from ACRES_640_PRODUCTION a,&lt;br /&gt;    (select recnmbr, PRODUCTION x1&lt;br /&gt;       from ACRES_640_PRODUCTION&lt;br /&gt;      where year = 1990&lt;br /&gt;        and product = 'G') b,&lt;br /&gt;    (select recnmbr, PRODUCTION x2&lt;br /&gt;       from ACRES_640_PRODUCTION&lt;br /&gt;      where year = 2000&lt;br /&gt;        and product = 'G') c&lt;br /&gt;where a.recnmbr = b.recnmbr&lt;br /&gt;and a.recnmbr = c.recnmbr&lt;br /&gt;and a.year in (1990,2000)&lt;br /&gt;and a.product = 'G'&lt;br /&gt;group by a.recnmbr&lt;br /&gt;union&lt;br /&gt;select distinct b.recnmbr RECNMBR,&lt;br /&gt;   19901 as PERCENTCHANGE&lt;br /&gt;from (select recnmbr,&lt;br /&gt;           PRODUCTION x1&lt;br /&gt;      from ACRES_640_PRODUCTION&lt;br /&gt;     where year = 1990&lt;br /&gt;       and product = 'G') b&lt;br /&gt;left outer join&lt;br /&gt;   (select recnmbr, PRODUCTION x2&lt;br /&gt;      from ACRES_640_PRODUCTION&lt;br /&gt;     where year = 2000&lt;br /&gt;       and product = 'G') c&lt;br /&gt;on b.recnmbr = c.recnmbr&lt;br /&gt;where b.x1 is not null&lt;br /&gt;and c.x2 is null&lt;br /&gt;union&lt;br /&gt;select distinct c.recnmbr RECNMBR,&lt;br /&gt;   20001 as PERCENTCHANGE&lt;br /&gt;from (select recnmbr,&lt;br /&gt;           PRODUCTION x1&lt;br /&gt;      from ACRES_640_PRODUCTION&lt;br /&gt;     where year = 1990&lt;br /&gt;       and product = 'G') b&lt;br /&gt;right outer join&lt;br /&gt;   (select recnmbr,&lt;br /&gt;           PRODUCTION x2&lt;br /&gt;      from ACRES_640_PRODUCTION&lt;br /&gt;     where year = 2000&lt;br /&gt;       and product = 'G') c&lt;br /&gt;on c.recnmbr = b.recnmbr&lt;br /&gt;where c.x2 is not null&lt;br /&gt;and b.x1 is null )&lt;/pre&gt;&lt;br /&gt;Don't be frightened! The query should be broken up into three parts. The first part will compute the percent change between year 1990 and year 2000 for all the sections where we have gas production in 1990 and in 2000 (&lt;b&gt;and a.year in (1990,2000)&lt;/b&gt;). Parts 2 and 3 of the union are specifically for sections that produce in one year, but not the other. The final map looks like...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/oil_gas_vc1990_2000_1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/400/oil_gas_vc1990_2000_1.jpg" alt="" border="0"&gt;&lt;/a&gt;&lt;br /&gt;Areas in red are places where gas production increased from 1990 to 2000. Areas in blue show a precent decreases. Areas in green did not produce in 1990. Areas in orange stopped producing by 2000. Email &lt;a href="mailto:jbartley@kgs.ku.edu"&gt;me&lt;/a&gt; if you have any questions.&lt;br /&gt;&lt;br /&gt;Next time we will look at sea-surface temeratures through time.   I know you can't wait!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15655029-113021112721196985?l=geosql.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geosql.blogspot.com/feeds/113021112721196985/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=15655029&amp;postID=113021112721196985' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/113021112721196985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/113021112721196985'/><link rel='alternate' type='text/html' href='http://geosql.blogspot.com/2005/11/power-of-spatial-to-attribute-join.html' title='The Power of the Spatial to Attribute Join-Part 1'/><author><name>Jeremy</name><uri>http://www.blogger.com/profile/06135435775056095723</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15655029.post-112483417733268508</id><published>2005-08-23T16:56:00.000-05:00</published><updated>2005-11-02T08:37:28.743-06:00</updated><title type='text'>Oracle Analytics to the rescue!</title><content type='html'>Hi All-&lt;br /&gt;&lt;br /&gt;This is a great example of taking a traditional database setup that is not intimately integrated with GIS and "spatially enabling" it. I have been working on a web-based application that will map out areas in Kansas where (spatial) irrigators are authorized to irrigate. Here is a partial example of what I have from the database for Lane county, Kansas:&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;location                 net_acres&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22NENW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22NESE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22NESW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22NWNE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22NWNW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22NWSE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22NWSW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22SENE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22SENW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22SESE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22SESW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22SWNE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22SWNW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22SWSE            30&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W22SWSW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23NENE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23NENW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23NESE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23NESW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23NWNE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23NWNW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23NWSE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23NWSW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23SENE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23SENW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23SESE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23SESW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23SWNE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23SWNW            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23SWSE            40&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;17S28W23SWSW            40  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The "location" is the legal description (&lt;a href="http://www.kgs.ku.edu/Publications/pic20/pic20_1.html"&gt;PLSS&lt;/a&gt;) of the area (down to 40 acre tracts; Township, Range, Section, Quarter, Quarter). The "net_acres" is the total amount that is authorized for that quarter-quarter section of land (up to 40 acres). The final map needs to display whether or not the quarter-quarter section is authorized for the full amount (40 acres) or whether it is only authorized for part of the quarter-quarter section (&amp;lt; 40).&lt;br /&gt;&lt;br /&gt;To do this we need to join the legal description table with a spatial feature class (&lt;a href="http://www.esri.com/software/arcgis/arcsde/index.html"&gt;SDE&lt;/a&gt; layer) of the legal land parcels.  We can do a straight join to a spatial layer of 40 acres polygons (PLSS Q1, Q2) in ESRI´s &lt;a href="http://www.esri.com/software/arcgis/arcims/index.html"&gt;ArcIMS&lt;/a&gt; fairly easily.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;&amp;lt;LAYERDEF id="acres_640" visible="true" &amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;  &amp;lt;SPATIALQUERY searchorder="attributefirst"&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;           where="PLSS.ACRES_40.TRS = WIMAS.POU_LANE.LOCATION"&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;     jointables="WIMAS.POU_LANE"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;  &amp;lt;VALUEMAPRENDERER lookupfield="WIMAS.POU_LANE.TRACT" &amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;  &amp;lt;EXACT value="Whole Tract" label="Whole Tract"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;    &amp;lt;SIMPLEPOLYGONSYMBOL fillcolor="0,128,0" boundary="false" /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;  &amp;lt;/EXACT&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;  &amp;lt;EXACT value="Partial Tract" label="Partial Tract"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;    &amp;lt;SIMPLEPOLYGONSYMBOL fillcolor="0,255,0" boundary="false" /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;  &amp;lt;/EXACT&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;  &amp;lt;/VALUEMAPRENDERER&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:Courier New;font-size:85%;"  &gt;&amp;lt;/LAYERDEF&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This would be efficient if we did not have very large dataset, but some counties in Kansas can have more than 20,000 40-acre tracts! An attribute table join to a spatial table like this would not be efficient enough for the web.&lt;br /&gt;&lt;br /&gt;What can we do? Well if you look at table 1, you should see that there is a lot of repetition. If four quarter-quarter sections have the same value then why not join the attribute to the quarter section SDE layer (160 acres; four 40-acre tracts)? To do this we need use SQL to aggregate our results. This is where Oracle´s analytical functions come in very handy! Analytical functions are extremely powerful. I am not going to do them justice here, but if you want more information go to &lt;a href="http://asktom.oracle.com/"&gt;AskTom&lt;/a&gt; or to a great &lt;a href="http://technology.amis.nl/blog/index.php?p=174"&gt;introduction to Analytical functions&lt;/a&gt; by AMIS in the Netherlands.  A key thing to remember about analytical functions is that they are done &lt;em&gt;at the end of the sql statement, &lt;/em&gt;just before the order by clause. So you are not limiting your results on the first pass with the use of analytical functions, but are doing inline analysis on the rows you have selected based on your criteria.&lt;br /&gt;&lt;br /&gt;Here is an example:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/image1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/320/image1.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;span style=";font-family:Courier New;font-size:78%;"  &gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So the POU_LANE is a view that contains the data from the first table. What we want to do is use the "partition by" feature to aggreagte data within the current selection set.&lt;br /&gt;&lt;br /&gt;&lt;blockquote  style="font-weight: bold;font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;first_value(substr(location, 1, 10))&lt;br /&gt;over (partition by substr(location, 1, 10) ) a_160&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;This part of the query groups (partition by) the first 10 characters of the location string (this would be the 160 acre polygons) and sets all rows of each group equal to the first value (first_value) that is recorded for each group. The difference between this and a traditional group by is that we can do this partition for each column in a recordset. This methodology can be very powerful if you think about.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;       count(distinct sign(net_acres - 40))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;         over (partition by substr(location, 1, 10)) dc_160,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This part of the query does the same partition as above, except that it computes a count for the distinct irrigation tracts--whole tract (sign of 0) or partial tract (sign of -1).&lt;br /&gt;&lt;br /&gt;&lt;blockquote  style="font-weight: bold;font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt; count(sign(net_acres - 40))&lt;br /&gt;over (partition by substr(location, 1, 10)) tc_160,&lt;/span&gt;&lt;/blockquote&gt;Here I am looking for a count of the number of 40 acre quarter-quarter sections in the 160 acre quarter sections. Again I am partitioning the records by the location (first 10 characters) within an individual column.&lt;br /&gt;&lt;br /&gt;Now we take the information from the analytical functions and perform our logic.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/finalquery.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/320/finalquery.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;&lt;br /&gt;select distinct&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;   case when dc_640 = 1 and tc_640 = 16 then a_640&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;        when dc_160 = 1 and tc_160 = 4 then a_160&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;        else location&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;    end location&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here is the logic part of the query. I am using the case function in Oracle. Case allows you to perform if/then/else statements on a per row basis on your query results. So...&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;If there is only 1 distinct value (either whole tract or partial tract) in the dc_640 column and there are a total of 16 rows (16 rows that have the same a_640 value) in the tc_640 column then the row value is equal to the 8 character section identifier (a_640)&lt;/li&gt;   &lt;li&gt;If there is only 1 distinct value (either whole tract or partial tract) in the dc_160 column and there are a total of 4 rows (4 rows that have the same a_160 value) in the tc_160 column then the row value is equal to the 10 character quarter-section identifier (a_160)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;If neither of the above are true then the location value is the full quarter-quarter-section.&lt;br /&gt;&lt;/li&gt; &lt;/ul&gt; Slap a distinct on the row and we have reduced our mapping component from 32 40-acre polygons to 4 40-acre, 3 160-acre, and 1 640-acre polygon. This doesn't sound like much, but this example has only looked at 2 640-acre sections. For large irrigation counties in Kansas like Finney, I can reduce over 11,000 40-acre tracts to 3200 multi-sectional tracts.&lt;br /&gt;&lt;br /&gt;Finally we take the query above and put it into a view and, in ArcIMS, perform a join between the SDE spatial feature class layer and each legal grouping (640 acres, 160 acres, &amp; 40 acres).&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/arcrequest.jpg"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/320/arcrequest.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Finally after all that we have a map....&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7515/1455/1600/map.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7515/1455/320/map.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I hope this was useful. If you have any questions, please feel free to post a comment. Oracle Analytical functions are a bit complicated at first, but once you understand them they can be extremely powerful and useful.&lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;&lt;br /&gt;Jeremy&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15655029-112483417733268508?l=geosql.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geosql.blogspot.com/feeds/112483417733268508/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=15655029&amp;postID=112483417733268508' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/112483417733268508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/112483417733268508'/><link rel='alternate' type='text/html' href='http://geosql.blogspot.com/2005/08/oracle-analytics-to-rescue.html' title='Oracle Analytics to the rescue!'/><author><name>Jeremy</name><uri>http://www.blogger.com/profile/06135435775056095723</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-15655029.post-112467806637157826</id><published>2005-08-21T21:22:00.000-05:00</published><updated>2005-08-21T21:34:26.376-05:00</updated><title type='text'>SQL for Geographers</title><content type='html'>Hi All-&lt;br /&gt;&lt;p class="Achievement" style="margin-left: 0in; text-indent: 0in;"&gt;This blog is dedicated to the integration between GIS and enterprise level relational databases. I am a Geographer by trade with a strong interest in relational databases. I have been in the GIS field for 10+ years and the database field for 7. The amount of data waiting to be spatially enabled within enterprise databases is extraordinary. I hope to show in this blog working examples of database-GIS interaction. Many examples that I will show are implemented within Oracle 9.2 and ESRI's SDE 8.3. Hopefully most of the SQL algorithms will transfer to your implementation. Stay tuned for more...&lt;br /&gt;&lt;/p&gt;  Jeremy&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15655029-112467806637157826?l=geosql.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geosql.blogspot.com/feeds/112467806637157826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=15655029&amp;postID=112467806637157826' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/112467806637157826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15655029/posts/default/112467806637157826'/><link rel='alternate' type='text/html' href='http://geosql.blogspot.com/2005/08/sql-for-geographers.html' title='SQL for Geographers'/><author><name>Jeremy</name><uri>http://www.blogger.com/profile/06135435775056095723</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
