Я поискал в dbi
документации и в гугле, но не смог найти, есть ли собственный (dbi) способ создания хеша списков. Самый близкий, который я могу придумать, это , fetchall_hashref
но он перезаписывает результаты, давая мне только то, что было последней парой. Для ясности, моя таблица представляет собой список пар чего-то вроде "id, tag". Я хочу сгруппировать все строки по id и вернуть хеш, где ключом является id, а "value" - это (ссылка на) список всех его тегов. Так что в случае:
id1, tag1
id1, tag2
id2, tag3
id2, tag1
Я хочу получить:
{'id1' => ['tag1', 'tag2'],
'id2' => ['tag3', 'tag1'] }
Возможно ли это? Если нет, то какой лучший (наиболее эффективный) способ сделать это не нативно? Очевидный подход — просто сделать комбинацию fetchall_* + push(), но есть ли способ получше?
решение1
Вот мой текущий подход:
my $ret = {};
foreach (@{ $sth->fetchall_arrayref( ) }) { # returns ref to array
push @{ $ret->{ $_->[0] } }, $_->[1] ;
}
return $ret;
Вдруг это кому-то пригодится, а мы пока подождем и посмотрим, есть ли лучший способ сделать это.
Редактировать:
Я нашел другой подход, который заключается в использовании GROUP_CONCAT
в MySQL для "тегов", соединенных с уникальным символом, который затем вы split()
в perl. Запрос будет примерно таким:
SELECT id, GROUP_CONCAT(tag, '|')
FROM mytable
GROUP BY tag
Затем на Perl:
my $ret = {};
foreach (@{ $sth->fetchall_arrayref( ) }) { # returns ref to array
push @{ $ret->{ $_->[0] } }, split("|", $_->[1]) ;
}
return $ret;
Код не проверен, поэтому применяются стандартные предупреждения.
Единственное преимущество, которое я вижу, это то, что это возвращает меньше строк из базы данных, и поэтому у вас меньше итераций foreach. Может быть, кто-то сможет профилировать этот код и сообщить нам, есть ли существенные различия в скорости в подходах.