2012-04-20 79 views
3

我有一個使用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

回答

2

這也取決於你如何構建你的整體腳本。您的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

2

該線路應該是一個循環:

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

7

有,你可以從一個語句句柄檢索數據許多不同的方式。最常見的是相當簡單,如下所示它們的用途:

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

2

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