【问题标题】:Load multiple csv file in oracle table from perl从perl在oracle表中加载多个csv文件
【发布时间】:2015-02-15 07:42:14
【问题描述】:

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

我认为我需要几天的时间才能让某些东西发挥作用,现在甚至无法考虑如何前进。

数据库: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
    

【问题讨论】:

  • 恭喜您使用use warningsuse strict 启动脚本。除此之外,您似乎在这里奇怪地混合了 Perl 4 和 shell 脚本。现在得走了,但如果我回来时你还没有收到答复,我会开始满足你的许多需求。
  • 你的问题到底是什么?
  • @tjd 感谢您的评论,是的,我知道我对这个编程很烂:),perl 4 不知道我在哪里使用它,我从我的 perl 5 书中拿走了大部分东西.
  • @AKHolland 基本上我正在尝试打开在昨天(周一)目录中创建的 csv 文件,插入到 Oracle 表中。
  • 这就是你想要做的。这不是一个真正的问题。

标签: perl csv oracle11g


【解决方案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_PPText::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
您需要 open() 您的文件(在 foreach 循环内),将其传递给 Text::CSV 元素(您可以在循环外声明您的解析器)

这是最简单的情况,您知道 CSV 的列号,如果您需要使用列名,则需要使用 getline_hr() 函数(请参阅 文本::CSV)
一旦你有了你的值(你应该在你的文件列表的 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]);

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

要捕获请求是否失败,您只需将 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 的值,您可以决定使用集成函数 commit 和 rollback 执行 commitrollback DBD::Oracle 模块 如果您不想计算插入次数,您只需在 $sth->execute 语句之后放置一个 $counter++ 有关 DBD::Oracle 的更多信息,我建议您阅读 CPAN 文档页面。

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

【讨论】:

  • 优秀的答案。我可能会推荐File::Findglob() 而不是opendir()
  • @doctori ,感谢您出色的回答和解释。我能够在日志文件中显示所有必需的 csv 文件。现在我正在尝试打开每个文件,读取并插入表格。我尝试使用 Text::csv 但它没有安装在我们的系统中。我在原始帖子中的@csvFile foreach my $file 中有文件数组,但这不喜欢 Text:csv .. 一次执行一项任务.. 目前试图弄清楚如何打开 csv 并写入以接受每个循环。
  • @tjd 和其他人,我怎样才能将 csvFile 完整位置放入 sub insertRecords ,打开,读取并将记录插入数据库?我可以成功地将所有需要的文件列出到@csvFile 数组中。
  • 您应该像这样将当前 $file 发送到您的函数: &insertRecords($file) 并在您的 sub 开头使用 my $fileToInsert = shift; 之类的内容检索它。 (如果您想要完整路径,您只需发送 $csvLogDir."/".$file)
  • @doctori 终于打印了第一列,移动得更远了。现在需要对插入进行排序并插入到数据库中。
猜你喜欢
  • 1970-01-01
  • 2016-05-11
  • 2013-07-25
  • 1970-01-01
  • 2014-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多