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

You guys have been instrumental to getting my database running. Now I don't know how to append a second database to my first using perl. Here is a summary of my problem:

I have Table1 with the following format:

int(10) auto_increment unique id
varchar(255) state
varchar(255) city
varchar(255) location
text discription

Table2 looks like:
int(10) auto_increment unique comment_id
int(10) id
text comments
varchar(255) name

Table1 is list of locations with a discription. Table2 is a table of peoples comments on locations listed in Table1. Each comment in Table2 is linked to its corresponding location in Table1 by id. Table1.id = Table2.id, there can be unlimited comments in Table2 that correspond to one location in Table1, so it's a one to many relationship. How can I query an print my Table1 data with my Table2 comments appended.

Here is an overview of how I'm printing my Table1 data, I need to figure out how to modifiy it.

$dbh = DBI->connect("DBI:mysql:$database:$db_server", $user, $password +); { $statement = "SELECT id,state,city,discription FROM speedtrap WH +ERE state=$state"; } $sth = $dbh->prepare($statement) or die "Couldn't prepare the query: " +.$sth->errstr; $rv = $sth->execute or die "Couldn't execute query: ".$dbh->errstr; print <<EOF; <table border="1" align="center" width="100%"> <tr> <td width="1" height="1"> <p align="center">ID</p> </td> <td width="10%" height="1"> <p align="center">State</p> </td> <td width="20%" height="1"> <p align="center">City</p> </td> <td width="20%" height="1"> <p align="center">Location</p> </td> <td width="20%" height="1"> <p align="center">Discription</p> </td> </tr> EOF while (@row = $sth->fetchrow_array) { ($id,$state,$city,$Discription) = @row; print <<EOF; <tr> <td width="1" height="1>$id</td> <td width="10%" height="1">$state</td> <td width="20%" height="1">$city</td> <td width="20%" height="1">$location</td> <td width="70%" height="1">$discription</td> </tr> EOF } print "</table>"; } $rc = $sth->finish; $rc = $dbh->disconnect;

Replies are listed 'Best First'.
Re: Perl database access
by jZed (Prior) on Sep 23, 2004 at 04:18 UTC
    Try somthing along the lines of:

      SELECT table1.id,state,city,discription,comment
        FROM table1 NATURAL LEFT JOIN table2
       WHERE state=$state
    

    Or else specify the id with a USING, ON, or WHERE clause.

Re: Perl database access
by ikegami (Patriarch) on Sep 23, 2004 at 05:00 UTC

    Update: Was missing a FROM clause

    my $dbh = DBI->connect( "DBI:mysql:$database:$db_server", $user, $password ); my $spdtrap_stmt = <<';'; SELECT id, state, city, discription FROM speedtrap WHERE state = ? ; my $comment_stmt = <<';'; SELECT comment_id, comments, name FROM comments WHERE id = ? ; # You need to make two dbh with many databases. # MySQL allows two queries to share the same dbh. # Create two dbh if need be. # Since we're using replaceable parameters, # We can prepare the comment sth once, and # executed multiple times. my $spdtrap_sth = $dbh->prepare($spdtrap_stmt) or die "Couldn't prepare the query: ".$DBI::errstr; my $comment_sth = $dbh->prepare($comment_stmt) or die "Couldn't prepare the comment query: ".$DBI::errstr; $spdtrap_sth->execute($state) or die "Couldn't execute query: ".$DBI::errstr; print <<EOF; <table border="1" align="center" width="100%"> <tr> <!-- why bother? -- <td width="1"> <p align="center">ID</p> </td> --> <td width="10%"> <p align="center">State</p> </td> <td width="15%"> <p align="center">City</p> </td> <td width="15%"> <p align="center">Location</p> </td> <td width="30%"> <p align="center">Description</p> </td> <td width="30%"> <p align="center">Comments</p> </td> </tr> EOF my @spdtrap_row; while (@spdtrap_row = $spdtrap_sth->fetchrow_array) { my ($id, $state, $city, $description) = @spdtrap_row; print <<EOF; <tr> <!-- why bother? -- <td>$id</td> --> <td>$state</td> <td>$city</td> <td>$location</td> <td>$description</td> <td><table border="0" width="100%"> <tr> <td width="70%">Comment</td> <td width="30%">By</td> </tr> EOF $comment_sth->execute($id) or die "Couldn't execute comment query: ".$DBI::errstr; my @comment_row; while (@comment_row = $comment_sth->fetchrow_array) { my ($comment_id, $comment_text, $commenter_name) = @comment_row; print <<EOF; <tr> <td>$comment_text</td> <td>$commenter_name</td> </tr> EOF } print <<EOF; </table></td> </tr> EOF } print "</table>"; $comment_sth->finish; $spdtrap_sth->finish; $dbh->disconnect;

    Fixes:

    • btw, the word is spelled "description". I didn't correct it in the database field name.
    • The height of every row was 1 pixel.
    • Your widths added up to more than 100%.
    • Your header widdths didn't match your field widths.
    • An error handler was using a handle that was undef.
    • You weren't escaping $state or even putting it in quotes. I don't see how that statement could ever execute. I used replaceable parameters, so no more need to quote or escape.

    output:

      Awesome, looks good. I get it. You guys always get it right when I'm in a crunch.

      How does this statement work:

      my $spdtrap_stmt = <<';'; SELECT id, state, city, discription FROM speedtrap WHERE state = ? ;
      Does it mean everything is really on the same line?

        You're welcome

        <<';' is just like the <<EOF you've used elsewhere in your program, except the single quotes mean $ and @ won't be treated as variables, and it's ends with a line containing only ';' (and no spaces). In other words, the statement in question compiles to exactly the same as:

        my $spdtrap_stmt = 'SELECT id,' . "\n" . ' state,' . "\n" . ' city,' . "\n" . ' discription' . "\n" . ' FROM speedtrap' . "\n" . ' WHERE state = ?' . "\n";

        SQL doesn't care about tabs (not used) and newlines outside of quote strings; it just treats them as another space. So the statement in question is functionally equivalent to what's below, but easier way to read:

        my $spdtrap_stmt = 'SELECT id, state, city, discription FROM speedtrap + WHERE state = ?';
      I'm running the code you suggested and got it to work. Now if there is a comment I want to print the comment, if there isn't I want to say that there aren't any comments:
      $comment_sth->execute($id) or die "Couldn't execute comment query: ".$ +DBI::errstr; my @comment_row; while (@comment_row = $comment_sth->fetchrow_array) { my ($speedtrap_id,$comment_id,$comment_text,$comment_date,$commenter) += @comment_row; if(@comment_row){ print <<EOF; <tr> <td colspan="2" bgcolor="#E6ECF0">$comment_text</td> </tr> EOF } else { print <<EOF; <tr> <td colspan="2" bgcolor="#E6ECF0">There are no comments from others fo +r this speedtrap.</td> </tr> EOF }

      But it always executes the the first condition. I've tried all kinds of ways to get the condition to work but I can't figure it out. Your help is greatly appreciated.

      Thanks
      Adam

        The problem is you'll only get into the while if @comment_row is true, so testing if (@comment_row) inside the while is useless.

        $comment_sth->execute($id) or die "Couldn't execute comment query: ".$DBI::errstr; my @comment_row; my $comment_count; while (@comment_row = $comment_sth->fetchrow_array) { my ($speedtrap_id,$comment_id,$comment_text,$comment_date,$commente +r) = @comment_row; $comment_count++; print <<EOF; <tr> <td colspan="2" bgcolor="#E6ECF0">$comment_text</td> </tr> EOF } print <<EOF unless ($comment_count); <tr> <td colspan="2" bgcolor="#E6ECF0">There are no comments from others fo +r this speedtrap.</td> </tr> EOF