Harch84 has asked for the wisdom of the Perl Monks concerning the following question:

Hi guys need some serious help I have a PostgreSQL database full of bus routes and bus stops. I am drawing them out using perl and manipulating the data. What I need to be able to do is to compare the variables from one query to the variables in another. Allow me to explain further. Firstly all unique routes are selected within a specific distance of my origin point.
$originsql = qq{ SELECT a.stop_reference, b.service_id, distance(Point +FromText('POINT($origin)', 27700),east_north), c.route_number FROM bu +s_stops a, service b, routes c WHERE distance(PointFromText('POINT($o +rigin)', 27700),east_north) < 200 AND a.stop_reference = b.stop_refer +ence AND b.service_id = c.service_id ORDER BY b.service_id, distance( +PointFromText('POINT($origin)', 27700),east_north)}; $sth = $dbh->prepare( $originsql ); $sth->execute(); $sth->bind_columns( undef, \$origin_stops, \$origin_service, \$origin_ +distance, \$origin_route_number); while ($sth->fetch()) { if ($orig_service != $last_service_id) { print "The bus stop located nearest to your Origin area is: " +.$origin_stops."<br />\n"; print "And the bus stop is ".$origin_distance." metres away from y +our location <br />\n"; print "This stop serves route number ".$origin_route_number." <p>< +p/>\n"; $last_orig_service_id = $origin_service; } }
The same logic is applied to the destination point with a similar query:
$destsql = qq{ SELECT a.stop_reference, b.service_id, distance(PointFr +omText('POINT($dest)', 27700),east_north), c.route_number FROM bus_st +ops a, service b, routes c WHERE distance(PointFromText('POINT($dest) +', 27700),east_north) < 200 AND a.stop_reference = b.stop_reference A +ND b.service_id = c.service_id ORDER BY b.service_id, distance(PointF +romText('POINT($dest)', 27700),east_north)}; $sth = $dbh->prepare( $destsql ); $sth->execute(); $sth->bind_columns( undef, \$destination_stops, \$destination_service, + \$destination_distance, \$destination_route_number); while ($sth->fetch()) { if ($dest_service != $last_service_id) { print "The bus stop located nearest to your Origin area is: " +.$destination_stops."<br />\n"; print "And the bus stop is ".$destination_distance." metres away f +rom your location <br />\n"; print "This stop serves route number ".$destination_route_number." + <p><p/>\n"; $last_dest_service_id = $destination_service; } }
Now what I need to be able to do is the compare the "$origin_service" to the "$destination_service". Now a simple if($origin_service == $destination_service) clause wont work as it seems to only compare the last two routes from each query whereas I need it to loop through all of the results for each and find matching pairs. One idea I had was to enter each origin and destination service numbers into two arrays and then compare them both? Or would I need some sort of double foreach statement to loop through both the origin and destination numbers finding mathcing pairs? I have tried many optins but cant seem to figure it out! Your help will be much appreciated. Thanks

Replies are listed 'Best First'.
Re: Comparing two variables from different loops
by almut (Canon) on Jul 05, 2007 at 01:30 UTC

    Your description sounds like you might want to build up a hash in the first while loop, with keys being $origin_service. Then you could check in the second loop whether a $destination_service is found among the origin services... (exists $services{$destination_service}).

    BTW, it seems to me you've got a few typos in your code (e.g. $dest_service vs. $destination_service) — I could be wrong though...   Anyway, using strictures might help with that.

Re: Comparing two variables from different loops
by GrandFather (Saint) on Jul 05, 2007 at 01:32 UTC

    Often the answer to "compare this list with that list" is to populate a hash from one list and then look it up using items from the second list.

    If you provide two lists with maybe 5 items in each and show us how you want to compare items from each list we may be able to help more. Trim each item down to just enough to demonstrate the problem btw.


    DWIM is Perl's answer to Gödel
Re: Comparing two variables from different loops
by Anonymous Monk on Jul 05, 2007 at 01:59 UTC
    OK as requested here is some more information and a small example of the data I am looking to compare with. An example of the output of the first SQL queries I have given is this:
    stop_reference | service_id | distance | route_number ----------------+------------+------------------+-------------- 8888888888 | 2 | 137.74251340817 | 2 1010101010 | 3 | 77.3369252039412 | 3
    Now what I wan to do is search through this table and comparing the service_id here to the service id of the next table. The next table comes from a query where all routes are selected with stops at a certain distance away from our route. What I need to be able to do is to find the matching service id of these two tables and then use a print statement to print the associated information:
    $connectsql = qq{SELECT b.service_id, d.stop_a, d.stop_b FROM bus_stop +s a, routes b, service c, topology d WHERE a.stop_reference = c.stop_ +reference AND c.service_id = b.service_id AND a.stop_reference = d.st +op_a ORDER BY a.stop_reference}; $sth = $dbh->prepare( $connectsql ); $sth->execute(); $sth->bind_columns( undef, \$connect_service, \$connect_stop, \$servic +e_stop ); while( $sth->fetch() ) { print..... } service_id | stop_a | stop_b ------------+------------+------------ 3 | 1010101010 | 8888888888 1 | 3333333333 | 6666666666 2 | 6666666666 | 3333333333 2 | 8888888888 | 1010101010
    Now while I can find if the last two service id's on each table match i need to be able to loop through them all and compare every row produced by the queries. Note the number of rows will be much larger this is just an example to work with for simplicity.
      Many others have suggested hashes, and that's definitely a valid approach. I'm curious, though, whether you couldn't achieve the same thing in SQL. That is, maybe you should just create a single query JOINing the two queries on service_id. That might reduce the amount of data you need to pull into Perl, and let the SQL server do the heavy lifting for you (which is what it's good at, after all).

        Please try the SQL given below. This SQL is NOT tested, but should return records with origin_service == destination_service. Please refer to Subqueries with ANY, IN, and SOME

        SELECT a.stop_reference, b.service_id, distance(PointFromText('POINT($origin)', 27700),east_north), c.route_number FROM bus_stops a, service b, routes c WHERE distance(PointFromText('POINT($origin)', 27700),east_north) < 200 AND a.stop_reference = b.stop_reference AND b.service_id = c.service_id AND b.service_id IN ( SELECT DISTINCT e.service_id FROM bus_stops d, service e, routes f WHERE distance(PointFromText('POINT($dest)', 27700),east_north) +< 200 AND d.stop_reference = e.stop_reference AND e.service_id = f.service_id ORDER BY e.service_id, distance(PointFromText('POINT($dest)', 27700),east_north) ) ORDER BY b.service_id, distance(PointFromText('POINT($origin)', 27700),east_north)

        --VC

Re: Comparing two variables from different loops
by Harch84 (Acolyte) on Jul 05, 2007 at 09:13 UTC
    So to clarify should I build one hash and then look up the keys of that hash using the other scalar variables? Or should i build two hashes, one for each query?

      You need just one hash. Something like this

      my %ids; my @orig_service_ids = (3,1,4,9,7,12); # this represents your first while ($sth->fetch) loop for my $id (@orig_service_ids) { $ids{$id} = 1; # instead of '1', you could also assign something else as value, # e.g. an anonymous array [...], or an anonymous hash {...}, to # store associated data, which you could then retrieve later... } # ... my @dest_service_ids = (1,5,8,11,7,2,9); # this represents your second while ($sth->fetch) loop for my $id (@dest_service_ids) { if (exists $ids{$id}) { print "ID $id exists in both origin and destination set\n"; # ... } }