Perl数据结构的问题没有创建HoA中断或HoH密钥

时间:2014-01-24 03:30:05

标签: perl hash-of-hashes

这是关于Perl数据结构的问题,但首先是涉及的一些细节的简要描述。我有一个使用DBI的perl脚本,并对mysql数据库执行三个查询($ q1 $ q2 $ q3)。每个查询返回2或3个字段(可能会根据要求进行更改)和任意数量的行。我的最终输出需要是所有字段及其值的csv。

以下表示从数据库返回的字段和行。

如果$ q1返回

field1   field2
id1      val_a
id2      val_w

$ Q2

field3               #note $q2 has returned one row
000

$ Q3

field4    field5    field6
val_b     val_c     val_d
val_x     val_y     val_z

然后csv将是

field1,field2,field3,field4,field5,field6
id1,val_a,000,val_b,val_c,val_d
id2,val_w,,val_x,val_y,val_z

我尝试使用像这样的数组哈希来收集数据

my @statements = ($q1,$q2,$q3);
my %HoA;
for (@statements) {

    my $sth = $dbh->prepare($_);
    $sth->execute;

    my $i=0;
    while(my @row = $sth->fetchrow_array) {
        push ( @{ $HoA{$i} }, @row[0..$#row] );
    $i++;
    }

}

我还在学习,所以我不确定这是否是最好的选择,虽然它一直在为我工作除了当一个或多个查询返回的行少于其他查询时,这是在上面的示例中说明了返回的字段和行。这会导致数据结构中断,行将相互碰撞。我也尝试了散列哈希,使用内部哈希键的字段

my @statements = ($q1,$q2,$q3);
my %HoH;
for (@statements) {

    my $sth = $dbh->prepare($_);
    $sth->execute;

    my $fields_ref = $sth->{NAME_lc};

    my $i=0;
    while(my @row = $sth->fetchrow_array) {
        my $v=0;
        for my $field (@$fields_ref) {
                    $HoH{$i}{$field}=$row[$v];
        $v++;
        }
    $i++;
    }
}

这会遇到另一个问题,不会创建不存在的行字段的内部键。因此,使用Data :: Dumper(在我的问题开头的示例中)的打印将如下所示:

      '0' => {
               'field1' => 'id1',
               'field2' => 'val_a',
               'field3' => '000',
               'field4' => 'val_b',
               'field5' => 'val_c',
               'field6' => 'val_d',
             },
      '1' => {
               'field1' => 'id2',
               'field2' => 'val_w',   # no field3
               'field4' => 'val_x',
               'field5' => 'val_y',
               'field6' => 'val_z',
             },

所以我有点陷入困境,不知道接下来要尝试什么...也许有一种方法可以保留field3的键并给它类似null的值?有什么帮助吗?

1 个答案:

答案 0 :(得分:0)

鉴于两个表以及将它们去标准化为一个.csv的一个合法原因,您应该使用您的DBMS而不是尝试自己滚动。如果夏娃没有车,有JOIN用于组合列'同步'和LEFT JOIN。在代码中:

use Modern::Perl;
use DBI;

my $dbh = DBI->connect("dbi:mysql:sotrials", "eh", "ohbnbwrg")
          || die "Could not connect to mysql:sotrials: $DBI::errstr";
$dbh->do("DROP TABLE IF EXISTS Car");
$dbh->do("DROP TABLE IF EXISTS Person");

$dbh->do("CREATE TABLE Person (Id INTEGER PRIMARY KEY, FName VARCHAR(30))");
$dbh->do("INSERT INTO Person VALUES (1, 'Adam')");
$dbh->do("INSERT INTO Person VALUES (2, 'Eve')");
$dbh->do("INSERT INTO Person VALUES (3, 'Abel')");
$dbh->do("CREATE TABLE Car (Id INTEGER PRIMARY KEY, Make VARCHAR(30), Owner INTEGER, FOREIGN KEY(Owner) REFERENCES Person(Id))");
$dbh->do("INSERT INTO Car VALUES (1, 'BMW', 1)");
$dbh->do("INSERT INTO Car VALUES (2, 'Honda', 3)");

my $sth;
$sth = $dbh->prepare("SELECT * FROM Person");
$sth->execute();
$sth->dump_results();
$sth = $dbh->prepare("SELECT * FROM Car");
$sth->execute();
$sth->dump_results();

my $fn = "./out.csv";

open(my $fho, '>', $fn) or die "Could not write open file '$fn' $!";
print $fho "FName;Car\n";
$sth = $dbh->prepare("SELECT P.FName, C.Make FROM Person P LEFT JOIN Car C On P.Id = C.Owner");
$sth->execute();
foreach my $row (@{$sth->fetchall_arrayref()}) {
    printf $fho "\"%s\";\"%s\"\n", @{$row};
}
close($fho);

$dbh->disconnect();

open(my $fhi, '<', $fn) or die "Could not read open file '$fn' $!";
print <$fhi>;
close($fhi);

输出:

perl 21323885.pl
'1', 'Adam'
'2', 'Eve'
'3', 'Abel'
3 rows
'1', 'BMW', '1'
'2', 'Honda', '3'
2 rows
Use of uninitialized value $row in printf at 21323885.pl line 32.
FName;Car
"Adam";"BMW"
"Eve";""
"Abel";"Honda"