0

这是一个关于 Perl 数据结构的问题,但首先是对所涉及的一些细节的简要描述。我有一个使用 DBI 并针对 mysql 数据库($q1 $q2 $q3)执行三个查询的 perl 脚本。每个查询返回 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值的东西?请问有什么帮助吗?

4

1 回答 1

0

给定两个表以及将它们反规范化为一个 .csv 的正当理由,您应该使用您的 DBMS,而不是尝试自己创建。如果 Eve 没有车,则有 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"
于 2014-01-24T18:30:02.483 回答