Perl DBI fetchall_hashref

9

考虑以下表格:

mysql> select * from vCountryStatus;
+-------------+------------+------+---------+--------+-----------------+
| CountryName | CountryISO | Code | Status  | Symbol | CurrencyName    |
+-------------+------------+------+---------+--------+-----------------+
| Brazil      | BR         |   55 | LIVE    | BRL    | Brazilian Real  |
| France      | FR         |   33 | offline | EUR    | Euro            |
| Philippines | PH         |   63 | LIVE    | PHP    | Philippino Peso |
+-------------+------------+------+---------+--------+-----------------+
3 rows in set (0.00 sec)

我想基于这张表构建一个哈希表。为此我会进行以下步骤:

#!/usr/bin/perl

use DBI;
use Data::Dumper;

my $dbh = DBI->connect("dbi:mysql:database=db", "user", "password", {RaiseError => 1, AutoCommit => 0, FetchHashKeyName => "NAME_lc"}) || die "DB open error: $DBI::errstr";

my $sth = $dbh->prepare("select * from vCountryStatus");
$sth->execute;
my $hash = $sth->fetchall_hashref('countryiso');
print Dumper($hash);

这是它生成的输出结果:
$VAR1 = {
          'PH' => {
                    'symbol' => 'PHP',
                    'status' => 'LIVE',
                    'countryname' => 'Philippines',
                    'countryiso' => 'PH',
                    'currencyname' => 'Philippino Peso',
                    'code' => '63'
                  },
          'BR' => {
                    'symbol' => 'BRL',
                    'status' => 'LIVE',
                    'countryname' => 'Brazil',
                    'countryiso' => 'BR',
                    'currencyname' => 'Brazilian Real',
                    'code' => '55'
                  },
          'FR' => {
                    'symbol' => 'EUR',
                    'status' => 'offline',
                    'countryname' => 'France',
                    'countryiso' => 'FR',
                    'currencyname' => 'Euro',
                    'code' => '33'
                  }
        };

问题是: 为什么哈希表的键(countryiso)在哈希表内部的值中被重复使用?
我希望得到以下输出:
$VAR1 = {
          'PH' => {
                    'symbol' => 'PHP',
                    'status' => 'LIVE',
                    'countryname' => 'Philippines',
                    'currencyname' => 'Philippino Peso',
                    'code' => '63'
                  },
          'BR' => {
                    'symbol' => 'BRL',
                    'status' => 'LIVE',
                    'countryname' => 'Brazil',
                    'currencyname' => 'Brazilian Real',
                    'code' => '55'
                  },
          'FR' => {
                    'symbol' => 'EUR',
                    'status' => 'offline',
                    'countryname' => 'France',
                    'currencyname' => 'Euro',
                    'code' => '33'
                  }
        };

能否使用fetchall_hashref DBI方法?或者我必须沿用传统的方法,遍历每一行并即时构建哈希表?


2
顺便提一下,prepare、execute和fetchall_hashref调用可以合并为一个selectall_hashref调用,像这样: my $hash = $dbh->selectall_hashref("select * from vCountryStatus", 'countryiso'); - Tim Bunce
如果有另一行的CountryISO值为PH,那么这两行都会被打印吗?如果不能,那么如何打印所有具有相同键的行? - Lucy
2个回答

3
不,无法使用fetchall_hashref实现此功能。但是你可以遍历哈希值并删除键:
delete $_->{countryiso} for values %$hash;

谢谢,这正是我所期望的。没什么大不了的,就像你说的,我可以删除它们,或者另一个解决方法是忽略它们,因为额外的内存开销(在我的情况下)非常小。 - emx
如果有另一行的CountryISO值为PH,那么这两行都会被打印吗?如果不是,那么如何打印所有具有相同键的行?需要使用while循环吗? - Lucy

1

我遇到了同样的问题,但是在fetchall_hashref中使用了多个键,所以我必须深入哈希引用。这并不是什么高深的科学,但是这就是解决方法:

(...)          
           my @keys=('key1','key2','key3');
           my $result_ref=$sth->fetchall_hashref(\@keys);

           remove_key_values($result_ref,\@keys);
(...)


sub remove_key_values {
    my ($href_values,$aref_keys) = (@_);

    foreach my $hk (keys %$href_values) {
        foreach my $ak (@$aref_keys) {
            if ($ak eq $hk) {
                delete $href_values->{$hk};
            }
        }
        if (exists $href_values->{$hk} and ref($href_values->{$hk}) eq 'HASH') {
                remove_key_values($href_values->{$hk},$aref_keys);
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接