如何用Perl對Excel的數據進行提取並分析


巡檢類工作經常會出具日報,最近在原有日報的基礎上又新增了一個表的數據量統計日報,主要是針對數據庫中使用較頻繁,數據量又較大的31張表。該日報有兩個sheet組成,第一個sheet是數據填寫,第二個sheet則是基於第一個sheet的數據進行的文字描述和圖表展示。

文字描述主要包括兩部分:一、呈現該31張表中數據量最大的9張表。呈現結果類似於:emp(約14萬),dept(約100萬)。。。當然,這個只是舉例,為了避免引起不必要的麻煩(主要是企業信息安全方面的考慮),我這里不可能將具體日報的內容貼出來。畢竟,這個會涉及到表名和數據量大小。二、相對於昨日,這31張表中有哪些表的數據量在今日有所增長。

對於這種機械類的工作,每次做起來都比較繁瑣,頭疼。Perl之父Larry Wall說過,懶惰、急躁、傲慢是程序員的三大美德。於是就着手寫了一個perl程序,每次只要把當天的數據量copy到Excel中,執行該程序即可。

程序內容如下:

use strict;
use Spreadsheet::XLSX;
use Unicode::UTF8simple;
use DateTime;
my ($col1,$col2,%hash1,%hash2,@tabname,$num,$num1);
my $dt=DateTime->from_epoch(epoch=>time);
my $duration=DateTime::Duration->new(days=>-1);
my $dt1=$dt+$duration;
my $date=$dt->month.'-'.$dt->day.'-'.substr($dt->year,2,2);
my $date1=$dt1->month.'-'.$dt1->day.'-'.substr($dt1->year,2,2);
my $uref =new Unicode::UTF8simple;
my $file='C:\Users\Victor\Desktop\需做數據遷移的數據表數據量巡檢日報-20150713.xlsx';
$file=$uref->fromUTF8('gb2312',$file);
my $workbook  = Spreadsheet::XLSX -> new ($file);
my $worksheet = $workbook->worksheet('數據填寫');
my ( $row_min, $row_max ) = $worksheet->row_range();
my ( $col_min, $col_max ) = $worksheet->col_range();
for my $col ( $col_min .. $col_max ){
    my $cell = $worksheet-> get_cell( 0, $col );
    next unless $cell;
    $col1=$col if ($cell->value() eq $date1);
    $col2=$col if ($cell->value() eq $date);
}
for my $row (1..$row_max){
    my $cell = $worksheet->get_cell($row,1);
    my $cell1= $worksheet->get_cell($row,$col1);
    my $cell2= $worksheet->get_cell($row,$col2);
    $hash1{$cell->value()}=$cell1->value();
    $hash2{$cell->value()}=$cell2->value();
    push @tabname,$cell->value();
}
print $uref->fromUTF8('gb2312',"(1)需做數據遷移的數據表當前數據量較大的依次為(不計日志表):\n");
my $str2=$uref->fromUTF8('gb2312','');
my $str3=$uref->fromUTF8('gb2312','');
my $str4=$uref->fromUTF8('gb2312','');
foreach my $key(sort {$hash2{$b}<=>$hash2{$a}} keys %hash2){
       printf "%s(%s%d%s)%s",$key,$str2,$hash2{$key}/10000,$str3,$str4;
       $num++;
       last if $num == 11;   
}
print "\n";
print $uref->fromUTF8('gb2312',"(2)務開通定單調度關鍵數據表數據量增長趨勢:\n");
foreach(@tabname){
    if($hash1{$_} < $hash2{$_}){
        print $_.$str4;
        $num1++;
    }
}
print $uref->fromUTF8('gb2312',"這$num1張表相對昨日有所增長。\n")

說明如下:

1> 在這里,用了三個模塊,其中Spreadsheet::XLSX用於讀取2007及以上版本的Excel。可惜的是,CPAN中貌似沒有一個模塊支持對已有Excel進行寫操作。具體在本例中,第二個sheet中的文字描述完全可以在第一個sheet中數據基礎上生成。但因找不到對既有Excel進行寫的模塊,所以生成的文字描述無法插入到第二個sheet中。於是只能退而求其次,只生成文字描述,然后再手動粘貼到第二個sheet中。第二個模塊是Unicode::UTF8simple,主要用於UTF8和其它字符集的轉換,在本例中,即中文字符集gb2312。第三個模塊是DateTime,用於構造今天的日期和昨日的日期。

2> 

my $dt=DateTime->from_epoch(epoch=>time);
my $duration=DateTime::Duration->new(days=>-1);
my $dt1=$dt+$duration;
my $date=$dt->month.'-'.$dt->day.'-'.substr($dt->year,2,2);
my $date1=$dt1->month.'-'.$dt1->day.'-'.substr($dt1->year,2,2);

用於構造今天的日期和昨日的日期,其中$date是今天的日期,$date1是昨天的日期。

3>

my $worksheet = $workbook->worksheet('數據填寫');
my ( $row_min, $row_max ) = $worksheet->row_range();
my ( $col_min, $col_max ) = $worksheet->col_range();
for my $col ( $col_min .. $col_max ){
    my $cell = $worksheet-> get_cell( 0, $col );
    next unless $cell;
    $col1=$col if ($cell->value() eq $date1);
    $col2=$col if ($cell->value() eq $date);
}

第一個sheet的名字是“數據填寫”,首先獲取該sheet行、列的范圍。

第一行的內容如下:

所以上面這個for語句用於獲取今日日期和昨日日期所在的列。

注意上面for語句中的next unless $cell,它的意思是如果$cell為空,則繼續下一個循環。因第一列第一行為空,所以該語句尤為必要。

4> 

for my $row (1..$row_max){
    my $cell = $worksheet->get_cell($row,1);
    my $cell1= $worksheet->get_cell($row,$col1);
    my $cell2= $worksheet->get_cell($row,$col2);
    $hash1{$cell->value()}=$cell1->value();
    $hash2{$cell->value()}=$cell2->value();
    push @tabname,$cell->value();
}

分別構造兩個哈希表,鍵均是第一列的表名,值是對應的數據量大小。其中hash1對應的是昨日的數據量,hash2對應的是今日的數據量。

將表名放到數組中,用於后續今日和昨日數據量的比較。

5> 

print $uref->fromUTF8('gb2312',"(1)需做數據遷移的數據表當前數據量較大的依次為(不計日志表):\n");
my $str2=$uref->fromUTF8('gb2312','');
my $str3=$uref->fromUTF8('gb2312','');
my $str4=$uref->fromUTF8('gb2312','');
foreach my $key(sort {$hash2{$b}<=>$hash2{$a}} keys %hash2){
       printf "%s(%s%d%s)%s",$key,$str2,$hash2{$key}/10000,$str3,$str4;
       $num++;
       last if $num == 11;   
}

對hash2,即今天的數據量進行排序,打印出31個表中排名前11位的表,輸入結果形式如下:

EMP(約1100萬)、DEPT(約1000萬)、location(約812萬)、sales(約123萬)...

因“約”、“萬”、“、”均是中文字符,所以需要轉換。因數據量的單位是萬,在這里,我們將$hash2{$key}的值除以10000。

6>

print "\n";
print $uref->fromUTF8('gb2312',"(2)務開通定單調度關鍵數據表數據量增長趨勢:\n");
foreach(@tabname){
    if($hash1{$_} < $hash2{$_}){
        print $_.$str4;
        $num1++;
    }
}
print $uref->fromUTF8('gb2312',"這$num1張表相對昨日有所增長。\n")

構造文字描述的第二部分,將今日相對於昨日數據量有所增加的表打印處理。輸出結果類似於:

emp、dept、location、sales這4張表相對昨日有所增長。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM