agrupar dos columnas de DB en perl

I am writing a script which needs grouping and I can't do them in the SQL. I get my results as ArrayReference. My query to the DB returns something like this.

1234 TIN
32364 TIN
34367 BOX
87484 TIN
45674 BOX
45476 TIN
4575  BOX

I want them to be grouped like :

These are the list of BOX: 4575,45674,34367.

These are the list of TIN: 1234,32364,87484,45476.

¿Alguna sugerencia por favor?

preguntado el 08 de noviembre de 11 a las 13:11

Utilizar group by in your query .... else you will have run through all the rows returned, search for BOX and TIN and store them in separate array accordingly -

Group by could be used only if you use aggregate function in your query. And I cant do any aggregate function in my columns. I have given just the two of them as example. I am having more than 10 types to search for. And the code look convoluted with too many if conditions.Correct me if I am wrong on Group by in SQL . Thanks -

@SipraMoon - Nonsense, of course you can do some aggregation in your database. That's one of the things that an RDBMS was built for! -

2 Respuestas

If you insist on not using the database for this, then the following code will do the basic grouping.

# Assume data is in @rows
my %group;
push @{ $group{$_->[1]} }, $_->[0] for @rows;

while (my ($key, $items) = each %group) {
    print "These are the list of $key: ". join(',', @$items) .".\n";

respondido 08 nov., 11:18

So exactly what does your array reference look like?

Is it an array of arrays like this:

@myArray = [

Or an array of hashes:

       =  [
                  NUMBER => 1234,
                  TYPE   => TIN,

Or is each row a single return of some form of fetch? There are five different ways to return data from a database using the DBI interface:

  • fetchrow_arrayref
  • fetchrow_array
  • fetchrow_hashref
  • fetchall_arrayref
  • fetchall_hashref

Asumiendo que usaste fetchall_arrayref, here's a sample program that will do what you want:

use strict;
use warnings;
use feature qw(say switch);
use Data::Dumper;

my $fetchedSqlData = [
                  [ qw(1234 tin) ],
                  [ qw(3434 box) ],
                  [ qw(4341 tin) ],
                  [ qw(2343 box) ],

my @tinList;
my @boxList;

foreach my $row (@{$fetchedSqlData}) {
    if ($row->[1] eq "tin") {
        push @tinList => $row->[0];
    else {
        push @boxList => $row->[0];


say "These are the list of BOX: " . join ", " => @boxList;
say "These are the list of TIN: " . join ", " => @tinList;

A better way would be to have a single hash based upon the value in column 2 and each hash would be a reference to an array:

my %typeHash;
foreach my $row (@{$fetchedSqlData}) {
    $typeHash{$row->[1]} = [] if not exist $typeHash{$row->[1]};
    push @{$typeHash{$row->[1]}} => $row->[0];

This is a bit more confusing, but would be more flexible incase you added a type "CRATE" to your list.

Printing out the data from this would be:

foreach my $type (sort keys %typeHash) {
    say "These are the list of $type: " . join ", " => $typeHash{$type}->[0];

BTW, I didn't test this hash of arrays, so expect coding errors. And, yes, I know I don't have to do $typeHash{$row->[1]) = [] if not exists $typeHash{$row->[1]}, but I like doing this because it makes sure I'm storing the right type of data in the hash element.

To thoroughly test this, I would have to build a database, and do a DBI fetchall_arrayref to verify exactly how the data is returned. I'm basing this off my erratic memory on how DBI worked when I last used it and the documentation.

There might be a way of doing this with map, but I generally haven't found map to be any more efficient than a simple loop.

respondido 08 nov., 11:20

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.