从perl加载oracle表中的多个csv文件

时间:2014-12-16 21:16:52

标签: perl csv oracle11g

经过一些研究后决定在这里提出更多专家答案的问题。我不能找到确切的情景作为我的问题,所以在这里......

我认为我需要几天时间才能开始工作,甚至不能考虑如何向前迈进。

DB:11gR2

操作系统:Unix

我尝试使用perl脚本将多个csv文件加载到Oracle表中。

  1. 列出我需要处理的所有csv,因为存在csv文件的目录包含许多其他文件。

  2. 打开csv文件并插入表格

  3. 如果有任何错误,则回滚该文件的所有插入并移至下一个文件

  4. 记录每个文件完成的插入次数

    #!/usr/bin/perl
    
    use warnings;    
    use strict;
    use Text::CSV;
    use DBD::Oracle;
    
    my $exitStatus = 0;
    my $dow     = `date +%a`; chomp $dow;
    my $csvDow  = `date -dd +%a`; chomp $csvDow;
    
    # define logfile
    my logFile;
    $logFile = "log.dbinserts"
    
    # define csv file directory
    my $csvLogDir  = "Home/log/$csvDow";
    
    # csv Files in array to list all possible match of file
     opendir(my $dh, $csvLogDir ) || die "can't opendir $csvLogDir : $!";
     my @csvFile = grep { /csv.*host1/ && -f "$csvLogDir/$_" } readdir($dh); chomp @csvFile;
     closedir $dh;
    
       foreach my $i (@csvFile)
          {
            $logFile (CSV File: $i);
          }
    
       foreach my $file (@csvFile) 
         {
           chomp ($item);
           $logFile-> ("Working under: $file");
           &insertRecords($csvLogDir."/".$file);
         }
    
    $logFile-> ("Exit status")
    
    #----------------
    
    sub insertRecords 
    {
     my $filetoInsert=shift;
     my $row;
    
     open my $fh, "<" or die "$fileToInsert: $!";
    
     my $csv = Text::CSV->new ({
        binary    =>1,
        auto_diag =>1,
       });
    
     while ($row = $csv->getline ($fh))
       {
          print "first column : $row->[0]\n,";
       }
     close $fh; 
    
     } 
    
    ========
    CSV File
    =========
    date, host, first, number1, number2
    20141215 13:05:08, S1, John, 100, 100.20
    20141215 13:06:08, S2, Ray, 200, 200.50
    ...
    ...
    ... 
    
    =========
    Table - tab1
    =========
    Sample_Date
    Server
    First
    N1
    N2
    

1 个答案:

答案 0 :(得分:1)

第一步取决于您需要选择CSV文件的标准 如果它在这些CSV的名称上,您只需使用opendir并获取readd的文件列表:

my $dirToScan = '/var/data/csv';
opendir(my $dh, $dirToScan ) || die "can't opendir $dirToScan : $!";
    my @csvFiles = grep { /.csv$/ && -f "$some_dir/$_" } readdir($dh);
closedir $dh;

在这个例子中,你将检索一个数组,其中包含所有以.csv结尾的文件(在设计目录中) 之后,您需要在阵列上使用foreach。

您可以找到更多示例和解释here   我不知道您的CSV的结构,但我建议使用像Text::CSV这样的模块,它是一个简单的CSV解析器,它将包装 Text :: CSV_PP Text :: CSV_XS ,如果它安装在您的系统上(它比PP版本更快(因为用perl / XS编写)
此模块允许您转换数组中的CSV行,如下所示:

 use Text::CSV;
 my $file = "listed.csv";
  open my $fh, "<", $file or die "$file: $!";

  my $csv = Text::CSV->new ({
      binary    => 1, # Allow special character. Always set this
      auto_diag => 1, # Report irregularities immediately
      });
  while (my $row = $csv->getline ($fh)) {
      print "first colum : $row->[0]\n";
      }
  close $fh;

来自:perlmeme.org
您需要打开()您的文件(在foreach循环中),将其传递给 Text :: CSV 元素(您可以在之外声明您的解析器)循环)

这是您知道CSV列号的最简单情况,如果您需要使用列名,则需要使用 getline_hr()功能(请参阅 Text :: CSV 的CPAN文档 一旦你掌握了你的价值(你应该在你文件列表的foreach循环中,并且在那里列出你的CSV行,你需要在数据库中插入这些数据。

为此,您需要 DBD :: Oracle 模块,以便您连接到数据库。
与每个DBI连接器一样,您需要使用以下语法实现连接:

 use DBI;
 $dbh = DBI->connect("dbi:Oracle:$dbname", $user, $passwd);

然后在你的循环中(当你读取CSV行时)你应该能够做到这样的事情:

$SQL = "INSERT INTO yourTable (foobar,baz) VALUES (?,?)";
$sth = $dbh->prepare($SQL);
$sth->execute($row->[0],$row->[1]);

这里有树步骤,您可以在其中准备请求,并将值替换为&#39;?&#39; (如果你有很多列,你也可以使用声明的变量) 在准备之后,您执行具有所需值的请求(再次,您不必使用匿名变量)

要捕获请求是否失败,您只需将RaiseError设置为声明连接时,看起来像这样:

 $dbh = DBI->connect("dbi:Oracle:$dbname", $user, $passwd, 
 {        
    PrintError => 1,
    PrintWarn  => 1,
    RaiseError => 1
   });

然后在播放请求时:

try
{
    $sth->execute($row->[0],$row->[1]);
 }
 catch
 {
    warn "INSERT error : $_";
    $CSVhasFailures = 1;
 };

您需要在每个CSV之前将$ CSVhasFailures的值设置为0 之后,通过在while循环结束时测试CSVhasFailures的值,您可以决定使用集成函数提交和回滚执行提交回滚。 DBD :: Oracle模块 如果你不计算插入的数量,你只需要在 $ sth-&gt;执行语句之后加上 $ counter ++ 有关DBD :: Oracle的更多信息,我建议您阅读 CPAN 文档页面。

最后一个建议,一步一步地开始:列出您的CSV文件,读取每个CSV的行,读取一列,打印一组列,然后将数据插入临时表中。