使用Perl获取所有记录DBI

问题描述:

我有一个使用DBI连接的Perl脚本。我打开并使用子例程读取SQL脚本文件。我打印的只有一条记录,我应该有两条记录(共三条记录)。我如何获得所有记录?使用Perl获取所有记录DBI

结果:

Alert:OUTBOUND_DATA:0 

脚本:

my $dbh_oracle = DBI->connect(
      $CFG{oracle_dbi_connect}, 
      $CFG{db_user}, 
      $CFG{db_cred}, 
      {AutoCommit => 0, 
      RaiseError => 0, 
      PrintError => 0}) or die ("Cannot connect to the database: ".$DBI::errstr."\n"); 

my ($val1, $val2) = get_data(); 
print "Alert:$val1:$val2\n"; 

send_email("Alert:$val1:$val2"); 

sub get_data 
{ 
    undef $/; 
    open (my $QFH, "< /sql/summary.sql") or die "error can't open this file $!"; 
    my $sth= $dbh_oracle->prepare(<$QFH>) or 
     die ("Cannot connect to the database: ".$DBI::errstr."\n"); 
    $sth->execute; 
    close $QFH; 
    my $row = $sth->fetchrow_hashref; 
    $sth->finish; 
    return @$row{'MYTABLE','FLAG'}; 
} 

sub send_email { 
    my $message = shift; 
    open (MAIL, "|/usr/sbin/sendmail -t") or die "Can't open sendmail: $!"; 
    print MAIL "To: me\@test.com\n"; 
    print MAIL "From: Data\n"; 
    print MAIL "\n"; 
    print MAIL $message; 
    close MAIL; 
} 
exit; 

从运行的查询结果:(超过1个REC)

MYTABLE     FLAG 
----------------------- ---------- 
OUTBOUND_DATA   0 
MSGS_BY_DIM     0 
INBOUND_DATA   0 

3 rows selected. 
+0

您可以设置'RAISEERROR => 1',且无需为那些死()调用。 – pilcrow 2012-04-21 00:21:03

+0

另外,我注意到你已经禁用了'RaiseError'和'PrintError'。第一个错误是致命的,第二个错误至少会打印出来(但不会杀死你的代码)。您应该至少将其中的一个设置为真实值,以免您的错误被丢弃。 – Ovid 2012-05-04 13:32:35

这也取决于你如何构建你的整体脚本。您的get_data()调用只允许返回一对值。我看到至少有几个选项:或者返回一个包含所有数据的散列(引用),然后让main进行汇编,或者使用前面提到的循环结构,并在子例程内部构造消息体,只返回一个标量字符串。

返回所有数据作为一个哈希参考,get_data子程序可能是这样的(请注意我用的fetchall_hashref代替fetchrow_hashref

sub get_data 
{ 
    undef $/; 
    open (my $QFH, "< /sql/summary.sql") or die "error can't open this file $!"; 
    my $sth= $dbh_oracle->prepare(<$QFH>) or 
     die ("Cannot connect to the database: ".$DBI::errstr."\n"); 
    $sth->execute; 
    close $QFH; 
    my $hash_ref = $sth->fetchall_hashref('MYTABLE'); 
    $sth->finish; 
    return $hash_ref; 
} 

你从main调用它,并使用输出如下:

my $hash_ref = get_data(); 
my $message = ""; 
foreach my $table (sort keys %$hash_ref) { 
    $message .= join(":", "Alert", $table, $$hash_ref{$table}{'FLAG'}) . "\n"; 
} 

这将导致含有$message

Alert:INBOUND_DATA:0 
Alert:MSGS_BY_DIM:0 
Alert:OUTBOUND_DATA:0 

而且你可能要礼貌地问:

$dbh_oracle->disconnect; 

你之前退出。

这有一些问题,例如你已经将SQL存储在一个外部脚本中,但是我已经使用硬编码密钥(MYTABLE,我认为它在您的查询中是唯一的)和值FLAG),当您想要扩展时,这将在稍后限制。

+0

这就是我一直在寻找的。我试图建立在使用子程序。感谢您提供'main'示例作为汇编所有输出的方式。 – cjd143SD 2012-04-21 02:50:13

该线路应该是一个循环:

my $row = $sth->fetchrow_hashref; 

它应该是:

my @rows; 
while (my $row = $sth->fetchrow_hashref) { 
    push @rows, $row; 
} 
return @rows; 

如果你宁愿有DBI为你做的回路中,检查出selectall_arrayrefselectall_hashref

+0

我在哪里放'$ sth-> finish'?那是在'return @ $ row'之后吗? – cjd143SD 2012-04-20 20:11:22

+0

@ cjd143SD,当你完成循环时,$ sth-> fetchrow_hashref将返回undef和“finish”本身。 – gpojd 2012-04-20 20:42:35

有,你可以从一个语句句柄检索数据许多不同的方式。最常见的是相当简单,如下所示它们的用途:

my @row_array = $sth->fetchrow_array; 
my $array_ref = $sth->fetchrow_arrayref; 
my $hash_ref = $sth->fetchrow_hashref; 

第一,fetchrow_array,将依次为阵列返回的每一行。如上所述使用来自选择返回的数据的一个例子可以是:

while (my @row_array = $sth->fetchrow_array) { 
    print $row_array[0], " is ", $row_array[1], " years old, and has a " , 
      $row_array[2], "\n"; 
} 

第二个例子是类似的,但返回的数组引用,而不是一个数组:

while (my $array_ref = $sth->fetchrow_arrayref) { 
    print $array_ref->[0], " is ", $array_ref->[1], 
      " years old, and has a " , $array_ref->[2], "\n"; 
} 

第三个例子,fetchrow_hashref,往往是最具可读性:

while (my $hash_ref = $sth->fetchrow_hashref) { 
    print $hash_ref->{name}, " is ", $hash_ref->{age}, 
      " years old, and has a " , $hash_ref->{pet}, "\n"; 
} 
+0

关于fetchrow_hashref的说明,除非您更改[FetchHashKeyName](http://search.cpan.org/~timb/DBI-1.618/DBI.pm#FetchHashKeyName)属性,否则这些键将被置为上限。 – gpojd 2012-04-20 20:44:45

+2

谢谢你的例子。 – cjd143SD 2012-04-20 22:24:38

fetchrow_方法实际上只是一次取一行。

如果您想要某些列的所有行,则可能无效率地推送数据结构或使用适合您情况的调用。

在我看来,要使用selectcol_arrayref为:

my $ary_ref = $dbh->selectcol_arrayref(
    "select id, name from table", 
    { Columns=>[1,2] } 
); 

列索引引用列的位置在结果集中,而不是原来的表。

您使用返回结果的方式也需要更改以处理所有返回的行。

此外,你必须:

sub get_data 
{ 
    undef $/; 

因为你啜包含SQL文件。但是,$/是一个全局变量。你应该在尽可能小的范围内使用local $/。所以:

my $sql = do { local $/; <$fh> }; 
+0

是的,我同意在这些情况下,我希望查询中的所有内容看起来像'selectcol_arrayref'将是您的选择。你对使用'local $ /'的建议,我会把它作为一个子程序还是将它留在外面?谢谢。 – cjd143SD 2012-04-21 01:35:15