Pesquisei nos dbi
documentos e pesquisei no Google, mas não consegui descobrir se havia uma maneira nativa (dbi) de criar um hash de listas. O mais próximo que consigo pensar é fetchall_hashref
que isso substitui os resultados, dando-me apenas o que foi o último par. Para esclarecer, minha tabela é uma lista de pares de algo como “id, tag”. Desejo agrupar todas as linhas por id e retornar um hash onde a chave é o id e o "valor" é uma (ref to) a lista de todas as suas tags. Então, no caso de:
id1, tag1
id1, tag2
id2, tag3
id2, tag1
Eu quero obter:
{'id1' => ['tag1', 'tag2'],
'id2' => ['tag3', 'tag1'] }
Isso é possível? Caso contrário, qual é a melhor (mais eficiente) maneira de fazer isso de forma não nativa? A abordagem óbvia seria apenas fazer uma combinação fetchall_* + push(), mas existe uma maneira melhor?
Responder1
Esta é minha abordagem atual:
my $ret = {};
foreach (@{ $sth->fetchall_arrayref( ) }) { # returns ref to array
push @{ $ret->{ $_->[0] } }, $_->[1] ;
}
return $ret;
Caso seja útil para alguém aí, enquanto esperamos para ver se existe uma maneira melhor de fazer isso.
Editar:
Encontrei outra abordagem, que é usar GROUP_CONCAT
no MySQL para as "tags", unidas com um caractere único, que depois você split()
em perl. A consulta seria algo como:
SELECT id, GROUP_CONCAT(tag, '|')
FROM mytable
GROUP BY tag
Então em perl:
my $ret = {};
foreach (@{ $sth->fetchall_arrayref( ) }) { # returns ref to array
push @{ $ret->{ $_->[0] } }, split("|", $_->[1]) ;
}
return $ret;
Código não testado, portanto, avisos padrão se aplicam.
A única vantagem que vejo é que isso retorna menos linhas do banco de dados e, portanto, você tem menos iterações do foreach. Talvez alguém possa traçar o perfil deste código e nos informar se há alguma diferença significativa de velocidade nas abordagens.