Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

mysql sorting

by sulfericacid (Deacon)
on Jun 01, 2005 at 05:57 UTC ( [id://462305]=perlquestion: print w/replies, xml ) Need Help??

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

This was asked in the CB but thought the answers would be easier through here.

You have a mysql database with a column "group". Group can contain nothing, unique values OR shared values with other similar rows of data within the same group.

Group SomeData --------------- red 1 yellow 2 green 3 purple 4 red 5 red 6 red 7 orange 8 green 9
How would you fetch all of the rows, sort them by the group column and THEN print a header of the group name for each unique group name? For example, the "group" from above would print out:
Green 3 9 Orange 8 Purple 4 Red 1 5 6 7 Yellow 2
The rows should be sorted by "group". Then each "group" has their own header (header would be a prinout of the group itself) which prints before the sql results.

Groups are dynamic so it can't be hard coded.

My idea:
-----------------------
Fetch the rows of the database and store all groups into a hash. Then from there, do a foreach sort and produce a new SQL query for each key.

It seems like this could work but if there's some odd hundred of unique groups, the overhead of all those queries is probably too pricey.

Any ideas or suggestions?



"Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

sulfericacid

Replies are listed 'Best First'.
Re: mysql sorting
by monarch (Priest) on Jun 01, 2005 at 06:06 UTC
    This is a problem I have come across several times, in fact often in the case of constructing HTML tables from a database.

    First:

    SELECT group, somedata FROM table ORDER BY group, somedata

    Next:

    my $lastgroup = undef; while ( my $row = $sth->fetchrow_arrayref() ) { if ( $lastgroup ne $row->[0] ) { print( $row->[0] . "\n" ); $lastgroup = $row->[0]; } print( " " . $row->[1] . "\n" ); }
    Update: I think setting $lastgroup initially to undef may be dangerous.. potenially a warning could be generated about using an undefined value in a comparison using the ne operator. So here is an update to the above routine that I think is safer:
    my $lastgroup = undef; while ( my $row = $sth->fetchrow_arrayref() ) { if ( ( !defined( $lastgroup ) ) || ( $lastgroup ne $row->[0] ) ) { print( $row->[0] . "\n" ); $lastgroup = $row->[0]; } print( " " . $row->[1] . "\n" ); }
      Hey,

      To select the individual groups only once, you can also use the DISTINCT clause for the select statement.

      Then you can use the results in a prepared cache to find the results for each individual group. monarch seems to have a correct solution also. But I'd thought I post something about the DISTINCT clause because it solves your first problem really well.
      my $dbh = DBI->connect('DBI:mysql:DB', 'user_n', $pass) or die "Failed + connecting to DB " . DBI->errstr; my ($groups, $results); my $sth = $dbh->prepare_cached(<<SQL); SELECT DISTINCT group from table SQL $sth->execute or die "executing: ", $dbh->errstr;; $sth->bind_columns(undef, \$groups); #bind the results--only contains unique group results. my $sth_x = $dbh->prepare_cached(<<SQL); SELECT somedata FROM table where group = ? SQL my $found = 0; my $found_x = 0; print "<b>$groups</b><hr>"; while ($sth->fetch) { $found++; $sth_x->execute($groups) or die "executing: ", $dbh->errstr; #find results using the results from the first query $sth_x->bind_columns(undef, \$results); while($sth_x->fetch) { $found_x++; print "$results<br>"; } unless($found_x) { print "empty for this group"; } print "<br>"; my $found_x = 0; #reset 2nd search found for next group result query. } unless ($found) { print "no groups matched"; }
      perleager
Re: mysql sorting
by BrowserUk (Patriarch) on Jun 01, 2005 at 06:01 UTC

    Somewhat off topic, but it sounds like you need to look at the group by clause.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.

      Actually, group by does very little in this case. Sort would work just fine for this situation (see monarch's answer ... that's the type of logic that I would use.)

      In these situations, I think the logic outside of the SQL is more important for the final presentation than something you can do through SQL.

      So, if 'group by' isn't useful here, what is it really good for? Well, it's good for when you're trying to aggregate records, such as the following.

      SELECT groupfield, SUM(somedata) FROM tablename GROUP BY groupfield

      or

      SELECT groupfield, MAX(somedata) FROM tablename GROUP BY groupfield

      In these situations, you only get one row returned per 'group'. There's also the rarely used (in my experience) HAVING clause.

        GROUP BY comes in very handy here, actually. (with MySQL's handy GROUP_CONCAT() function, versions 4.1 and up):
        SELECT Group, GROUP_CONCAT(SomeData ORDER BY SomeData SEPARATOR ',') FROM table GROUP BY `Group`
        In the OP's example, this would result in the following data that would be trivial to loop through and split on the separator chosen in your SQL:
        green 3,9 orange 8 purple 4 red 1,5,6,7 yellow 2
        -- Brian
Re: mysql sorting
by graff (Chancellor) on Jun 02, 2005 at 02:14 UTC
    my $sth = $dbh->prepare( "select group, somedata from sometable" ); $sth->execute; my $rowrefs = $sth->fetchall_arrayref; my %grouphash; for my $row ( @$rowrefs ) { push @{$grouphash{$$row[0]}}, $$row[1]; } for my $group ( sort keys %grouphash ) { print "$group\n"; print " $_\n" for ( sort @{$grouphash{$group}} ); }
    (not tested, but seems simple enough)

    updated to fix brackets on $$row[1] (I didn't mean to use curlies there).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://462305]
Approved by BrowserUk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (4)
As of 2024-04-20 00:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found