Generating a table & map sharing identifiers

Bill Binko bill at BINKO.NET
Fri Aug 26 12:08:46 PDT 2005


So, after getting nothing back but comments on my ASCII-art (mostly 
positive, amazingly :), I banged on this a while and have come up with a 
fairly simple solution.  I thought I'd post it back to the list, so it's 
below (after the problem statement)...

On Sun, 21 Aug 2005, Bill Binko wrote:

> Hi everyone,
> 
> I have a problem that I'd like some feedback on.  I'm certain it can be 
> done, but would like to know how others have solved it in the past.
> 
> I need to generate several tables with "nearest X items" to a location.  
> For example, "Nearest 5 Schools" to a location.  I then want to generate a 
> map showing the area that includes the X items and show the items on the 
> map using the id's from the table.
> 
> Here's an example:
> 
> Table:
> Map ID	|School Name	|Students | Teachers
> --------------------------------------------
> (A)	|Main St. Elem. |100	  | 10
> (B)	|Pinewood Elem. |2500	  | 20
> (C)	|Forrest Lakes  |800	  | 20
> 
> Map:
>  ------------------
> | (A)              |
> |              (B) |
> |     (C)          |
>  ------------------

So, I found that you can indeed solve this with a strictly PostGIS 
solution.  It still might not be the best, but since it works I thought 
I'd post it.

The trick is to write a PL/PGSQL function that returns a counter that is 
unique to the current session, but that doesn't involve any setup ahead of 
time (like createing a sequence).  Once you have that, you have to sort 
your shapes, and then add the counter to the results before they go back 
to mapserver.  If you add the counter and then sort, you won't get the 
results you want.

So, here's an example:

The original Layer showed the nearest 10 sinkholes to a point (if they 
were within 3 miles).  The POINT() below was actually found dynamically):

DATA "hole from (select oid, hole from FROM all_sinkholes_km \
      WHERE hole && buffer(pointfromtext('POINT(249895.731374337 1349408.0255176)', 26759),3*5280)
      ORDER BY distance(hole, pointfromtext('POINT(249895.731374337 1349408.0255176)', 26759)) 
      limit 10) as innerQ using unique oid using SRID=26759"

The code that generated the HTML table used a query with the same WHERE
clause, but selecting different info for the table.  However, it had the
same ORDER BY and LIMIT, so they were returned in the right order.

The goal was to add a column to the HTML table that had "MAP ID" as the 
header and "A", "B", etc. as the column values, and then to put "A","B", 
etc as the labels on the points returned on the map.

The DATA section was changed to this:

DATA "hole from (select oid, mapCounter('sinkhole', 'A') as label, hole 
                 FROM (select hole from all_sinkholes_km WHERE hole && 
                       buffer(pointfromtext('POINT(249895.731374337 1349408.0255176)',
				                   26759), 3*5280) 
                       ORDER BY distance(hole, pointfromtext('POINT(249895.731374337 1349408.0255176)', 26759)) 
                       limit 10) as innerQ) as outerQ using unique oid using SRID=26759"

This returns the same holes, but with a field named 'label' that has "A", 
"B", etc to use in the mapfile LABELITEM.

Here's the code to mapCounter()

CREATE OR REPLACE FUNCTION mapCounter(text, char) RETURNS text AS '
DECLARE
	seqName  ALIAS FOR $1;
	startChar ALIAS FOR $2;
	seqAvail integer;
	result text;
BEGIN
	seqAvail :=  count(*) from pg_class where relname = seqName AND pg_table_is_visible(oid);
	IF seqAvail = 0 THEN 
	   EXECUTE '' CREATE TEMPORARY SEQUENCE '' || seqName;
	END IF ;
	result := chr((ascii(startChar) - 1 + nextval(seqName))::integer);
	return result;
END;
' LANGUAGE plpgsql;

The function takes two parameters, a unique identifier that must be a 
valid PostgreSQL sequence name, and a starting character. It checks to see 
if there's already a temporary sequence of that name in the current 
session, and creates one if not, then it just returns the sequence.

I have found this very helpful for adding labels to CGI-type Mapserver 
apps, and think it would help in WMS/WFS services as well.

I hope this helps someone.

Bill



More information about the MapServer-users mailing list