【问题标题】:Batch inserts with Perl's DBI使用 Perl 的 DBI 进行批量插入
【发布时间】:2015-11-17 22:04:52
【问题描述】:

我正在尝试将数据行批量插入到 postgres 数据库中。

我认为,我将数据填充到数组 ref 中。它是使用 perl 脚本从使用Spreadsheet::BasicReadNamedColmodule 的空格分隔文件中获取的。获取数据的代码是

 $ss = new Spreadsheet::BasicReadNamedCol($xlsFileName) ||
 die "Could not open '$xlsFileName': $!";
 $ss->setColumns(@columnHeadings);

 my @array;

 my $row = 0;
 while (my $data = $ss->getNextRow())
 {
     $row++;

     push @array, "@$data";
 }

下面是数组 ref 的内容。

Cristan McX  123 W State Street North Aurora IL
William Sch  123 South Third St #367 Geneva IL
Kellie xxx  123 South East St. Gardner IL
John xx  321 Princeton Ct. Frankfort IL
Peter xxxxxxx  123 N Myrtle Avenue Elmhurst IL
Izabella xxx  321 S 3rd St. #367 Geneva IL

我用来插入的 Perl DBI 代码是:

my $dbh = DBI->connect("DBI:Pg:dbname=greenthumb;host=localhost;    port=5432","","", {'RaiseError' => 1});

my $sth = $dbh->prepare( 'INSERT INTO testtable (?, ?, ?, ?, ?, ?)' );

foreach(@array) { $sth->execute( @{$_} ); }
$sth->finish;

我得到的错误是:

Can't use string ("FirstName LastName BusinessName "...) as an ARRAY ref   while "strict refs" in use at ./f.pl line 38.

【问题讨论】:

  • $_ 不是一个数组,它是一个字符串。你可能想先split它。
  • 另外,如果真的是空格分隔,当它们包含空格时,你将如何区分字段,即123 W State Street North
  • 您还需要在值列表之前添加关键字VALUESINSERT INTO table_name VALUES ...。似乎您可能希望在循环中进行插入,该循环遍历电子表格内容,而不是字符串化和去字符串化。
  • $_ 不是一个数组引用,它是一个字符串。但是$data 是一个数组引用。你可以说push @array, $data

标签: perl postgresql


【解决方案1】:

不是一般的 DBI 解决方案,但由于您使用的是 PostgreSQL,因此您还可以使用“COPY”进行高效的批量插入,从电子表格中抓取每一行时添加:

...
$dbh->do("COPY testtable FROM STDIN");
while ( my $data = $ss->getNextRow ) {
    $dbh->pg_putcopydata(join("\t", @$data) . "\n");
}
$dbh->pg_putcopyend();

【讨论】:

    【解决方案2】:

    考虑到您在 cmets 中收到的建议并添加了我自己的一些更正,您的程序应该看起来像这样。我无法测试它,因为我是从平板电脑发帖的

    无需将整个电子表格读入内存——只需在从 XLS 文件中读取数据时将数据插入到数据库表中

    显然,您必须将列名替换为实际值。如果您只是想要电子表格中的所有数据,那么您应该使用Spreadsheet::BasicRead

    use strict;
    use warnings 'all';
    
    use DBI;
    use DBD::Pg;
    use Spreadsheet::BasicReadNamedCol;
    
    use constant XLS_FILE => 'myfile.xls';
    
    my $dbh    = DBI->connect( 'dbi:Pg:dbname=greenthumb;host=localhost;port=5432', '', '', { RaiseError => 1 } );
    my $insert = $dbh->prepare( 'INSERT INTO testtable VALUES (?, ?, ?, ?, ?, ?)' );
    
    my $ss = Spreadsheet::BasicReadNamedCol->new(
        fileName      => XLS_FILE,
        columns       => [ qw/ FirstName LastName BusinessName col4name col5name col6name / ],
        skipHeadings  => 1,
        skipBlankRows => 1,
    ) or die sprintf "Could not open '%s': %s", XLS_FILE, $!;
    
    while ( my $data = $ss->getNextRow ) {
        $insert->execute(@$data);
    }
    

    【讨论】:

      【解决方案3】:

      您从$ss->getNextRow 获得了一个数组引用,但您取消引用它并将数组推入数组时将其转换为字符串。

      push @array, "@$data";
      

      @$data 取消引用引用的数组,"..." 将取消引用的数组转换为字符串。)

      如果你只是推送你拥有的数组引用,那么一切都会正常工作。

      push @array, $data;
      

      但我喜欢Borodinanswer,因为它不需要中间的@array 并且可以一行一行地处理电子表格。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-01
        • 2023-04-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多