通过数组Perl SQLite DBI INSERT

时间:2014-08-11 21:47:18

标签: perl sqlite dbi

我有以下非常复杂的Perl代码,它由大小不等但通常在10到20行之间的动态数组提供。因此我在循环中运行它,但是估计必须有一种更优雅的方式来插入数据。

是否可以改进此代码以提高效率?

sub data_fill {

  my $target = shift;
  my (@input_data) = @_;

  # Delete the old data
  my $sth = $dbh->prepare("DELETE FROM work_data WHERE target = '$target' ");
  $sth->execute();

  # Insert the new data
  my $sql       = qq{INSERT INTO work_data (target, trackingno, temp, apple, orange, banana, strawberry, lettuce, apricot, peach, blackberry, melon, lemon) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)};
  my $sth       = $dbh->prepare($sql);
  my $arraysize = scalar(@input_data);
  my $i         = 0;

  while ($i < $arraysize) {

    $sth->bind_param(1, $target,             SQL_VARCHAR);
    $sth->bind_param(2, 'OK',                SQL_VARCHAR);
    $sth->bind_param(3, $input_data[$i],     SQL_VARCHAR);
    $sth->bind_param(4, $input_data[$i + 1], SQL_VARCHAR);
    $sth->bind_param(5, $input_data[$i + 2], SQL_VARCHAR);
    $sth->bind_param(6, $input_data[$i + 3], SQL_VARCHAR);
    $sth->bind_param(7, $input_data[$i + 4], SQL_VARCHAR);

    my $lettuce = $input_data[$i + 5];
    my $apricot = $input_data[$i + 6];
    my $peach   = $input_data[$i + 7];

    if (length($lettuce) == 0) {
      $lettuce = -1;
    }    # Safety net to help later in db sorting
    if (length($apricot) == 0) {
      $apricot = -1;
    }    # Safety net to help later in db sorting
    if (length($peach) == 0) {
      $peach = -1;
    }    # Safety net to help later in db sorting

    $sth->bind_param(8,  $lettuce,             SQL_INTEGER);
    $sth->bind_param(9,  $apricot,             SQL_INTEGER);
    $sth->bind_param(10, $peach,               SQL_INTEGER);
    $sth->bind_param(11, $input_data[$i + 8],  SQL_VARCHAR);
    $sth->bind_param(12, $input_data[$i + 9],  SQL_VARCHAR);
    $sth->bind_param(13, $input_data[$i + 10], SQL_VARCHAR);
    $sth->execute;

    $i = $i + 11;    # INCREMENT
  }
  $dbh->disconnect;
  return;
}

1 个答案:

答案 0 :(得分:2)

你的代码并不像复杂的那样复杂。

我看到的第一件事是每次子程序执行时都会调用$dbh->prepare。更糟糕的是,返回前有一个$dbh->disconnect

我还会看一下绑定,如果你将参数复制到一个静态数组而不是每次都绑定它们,这可能是永久性的。


<强>更新

这是为了解释我的意思。 unless语句中的代码只会执行一次 - 第一次调用data_fill子例程。它准备delete和insert语句,并将@params数组绑定到insert语句中的占位符。

请注意,preparebind_param来电不必在此子程序中。它们实际上是初始化的一部分,unless用于确保它们只执行一次。

完成所有设置之后,剩下的就是执行delete语句,然后从子例程参数列表中重复填充@params数组并执行insert语句。我完全删除了$dbh->close,因为它不是关闭数据库句柄的正确位置。

此解决方案中包含太多&#34;魔术数字&#34; ,我不会按原样发布它,但我不够了解你的要求总结我是否在正确的界限上。

请注意,除了检查它是否会编译

之外,这些都没有经过测试
my ($delete, $insert, @params);

sub data_fill {

  my $target = shift;
  my (@input_data) = @_;

  unless ($delete and $insert) {

    $delete = $dbh->prepare('DELETE FROM work_data WHERE target = ?');

    $insert = $dbh->prepare('
        INSERT INTO work_data (
          target, trackingno, temp, apple, orange, banana,
          strawberry, lettuce, apricot, peach, blackberry, melon, lemon
        )
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ');

    for my $i (0 .. 10) {
      my $mode = SQL_VARCHAR;
      $mode = SQL_INTEGER if $i >= 7 and $i <= 9;
      $sth->bind_param($i+1, $params[$i], $mode);
    }
  }

  $delete->execute($target);

  while (@input_data >= 11) {
    my @record = splice @input_data, 0, 11;
    @params = ($target, 'OK', @record);
    for (@params[7..9]) {
      $_ = -1 unless length > 0;
    }
    $insert->execute;
  }
}