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

This is a code tweaking question; a question to improve my coding skills. One of my web site runs almost totally on Perl CGI and DBI scripts. All data for the site is stored in MySQL. For each web page generated, I want to include meta-keywords for the search engines to use. These keywords are stored in a table in MySQL. For each CGI script, I call a subroutine located in a library file which queries the meta-keywords table for the keywords for a given script and its parameters. I need those keywords to be returned in a comma-separated list and in a string.

Here's an example of the line of code in the calling CGI script:

my $meta_keywords = &get_meta_keywords($script,$parameter);

Below is the code for the called subroutine:

sub get_meta_keywords { my ($script,$parameter) = @_; $sql_stmnt = "SELECT meta_keyword FROM site_meta_keywords WHERE script = ? AND parameter = ?"; $sth = $dbh->prepare($sql_stmnt); $sth->execute($script,$parameter); my $keywords = $sth->fetchall_arrayref(); $sth->finish(); my $meta_keywords = join(', ', @$keywords); return $meta_keywords; }

This returns the correct number of elements, separated by commas, but each element is an array and not text. I realize that this is part of the nature of the fetchall_arrayref() from DBI. However, I should think that there is a way I can dereference this, properly. For some background understanding, I created this simple script to test my use of join with a referenced array:

#!/usr/bin/perl -w my @keywords = qw(one two three); my $keywords = \@keywords; my $meta_keywords = join(',', @$keywords); print $meta_keywords, "\n"; exit;

The code above returns the following text:

one,two,three

The difference, of course and again, is that fetchall_arrayref() returns not only a reference to an array, but the array it references is an array of arrays. Meaning, although I'm only selecting one column in MySQL, I could as easily select multiple columns and thereby each element of the array that's referenced contains an array of all of the columns I select. In this case only one element is contained in each sub-array.

A simple solution to my problem would be to do the following:

sub get_meta_keywords { ... my @keywords; while(my ($keyword) = $sth->fetchrow_array()) { push(@keywords, $keyword); } $sth->finish(); my $meta_keywords = join(', ', @keywords); return $meta_keywords; }

This works just fine. If you've read this far, you may be wondering what is my question and what is my problem. It seems to me that I should be able to retrieve the whole array in one line and then dereference the array to the level I need, and not have to resort to a while statement. I know it's not that much extra code, but it seems amateurish and I'm trying to improve my coding skills. So, if you know a way to tighten up this code, please let me know. It seems like I should be able to do something like, $@keywords->[0] (which doesn't work either) inside the join. Please let me know if there is a way to do this or if there isn't anything better than using a while as I've done, so that I can give up. Thanks.

-Spenser

That's Spenser, with an "s" like the detective.

Replies are listed 'Best First'.
Re: join and fetchall_arrayref()
by Arunbear (Prior) on Apr 15, 2009 at 13:54 UTC
    You can use map to extract the keyword from each arrayref in the arrayref you get back from DBI:
    sub get_meta_keywords { my ($script,$parameter) = @_; $sql_stmnt = "SELECT meta_keyword FROM site_meta_keywords WHERE script = ? AND parameter = ?"; my $rows = $dbh->selectall_arrayref($sql_stmnt, undef, $script, $par +ameter); my $meta_keywords = join(', ', map { $_->[0] } @$rows); return $meta_keywords; }
      my $rows = $dbh->selectall_arrayref($sql_stmnt, undef, $script, $param +eter); return join(', ', map { $_->[0] } @$rows);
      can be replaced with
      my $meta_keywords = $dbh->selectcol_arrayref($sql_stmnt, undef, $scrip +t, $parameter); return join(', ', @$meta_keywords);
Re: join and fetchall_arrayref()
by targetsmart (Curate) on Apr 15, 2009 at 10:19 UTC
    1) use Data::Dumper to print the contents of $keywords, so that you know how to access the data inside it
    2) you are just talking about using 'fetchall_arrayref()' is amateurish, IMO it is not.
    3) see perllol to know about array of arrays and ways to access it.
    4) you are worrying about a problem, where it is not a problem at all. Concentrate on something else which is much important to you than this.

    UPDATE
    I'm trying to improve my coding skills
    try this
    Real Life Perl Exercises
    Recommended Reading


    Vivek
    -- In accordance with the prarabdha of each, the One whose function it is to ordain makes each to act. What will not happen will never happen, whatever effort one may put forth. And what will happen will not fail to happen, however much one may seek to prevent it. This is certain. The part of wisdom therefore is to stay quiet.