Perl sql查询语句

时间:2013-12-12 08:31:40

标签: sql sql-server perl

我的sql语句很简单,如下所示:

if not exists (select col_a from t_a where co_b = 'v_b')
begin
    insert into t_a (col_a  ,col_b  ) 
        VALUES(v_a,v_b)
end
else
begin
    update t_a set col_a = v_a, col_b = v_b where col_b = 'v_b'
end

由于我要更新数百行,如何以最低的时间成本在Perl中执行此操作?

如果我使用Prepare + Execute,如何使用占位符?编写语句?

$dbh->prepare($statement);是否支持多个复合SQL行,如上所述?或者我是否必须将行保存到sql文件中并使用SQL Server运行它?

为了使问题更清楚,我的Perl行看起来如下:

$statement = "if ... VALUES(?,?)...update t_a set col_a = ?, col_b = ?"; 
# better to use one binding values(v_a, v_b) couplets mapping 
# the 2 placeholders of insert and update both?
foreach (@$va_arr) {
    my $values_for_one_row = $_;            
    $dbh->prepare($statement);
    $execute->execute($values_for_one_row->{col_a }, $values_for_one_row->{col_b });
}

我忘记了一件事:'what'也是$ va_arr中每次迭代都要更改的值:如果不存在(从t_a中选择col_a,其中co_b ='v_b')。此外,更新部分应为:update t_a set col_a =?,col_b =?其中col_b =“v_b”。似乎没有更好的方法,然后包括准备进入循环?对不起,我认为这个例子没有完整。但我认为simbabque的答案已经足够好了。

3 个答案:

答案 0 :(得分:1)

您可以毫无问题地使用SQL。您需要准备一次声明。我假设您的$va_arr看起来像这样:

my $va_arr = [
  {
    col_a => 1,
    col_b => 2,
  },
  {
    col_a => 'foo',
    col_b => 'bar',
  },
];

运行此代码的代码如下。 请注意,您必须将col_n参数传递两次,因为每次执行时,每次?需要将它们填充两次。它们按查询中?的顺序填写,因此col_a需要col_bINSERTcol_a需要col_bUPDATE } my $sql = <<'EOSQL'; if not exists (select col_a from t_a where co_b = 'whatever') begin insert into t_a (col_a ,col_b ) VALUES(?, ?) end else begin update t_a set col_a = ?, col_b = ? end EOSQL my $sth = $dbi->prepare($sql); foreach ($values = @{ $va_arr }) { $dbh->execute($values->{col_a }, $values->{col_b }, $values->{col_a }, $values->{col_b }); }

my @columns = qw( col_a col_b col_c col_n );
my $va_arr = [
  {
    col_a => 1,
    col_b => 2,
    col_n => 99,
  },
  {
    col_a => 'foo',
    col_b => 'bar',
    col_n => 'baz',
  },
];

# build the sql dynamically based on columns
my $sql = q{
if not exists (select col_a from t_a where co_b = 'whatever')
begin
    insert into t_a (} . join(',' @columns) . q{) 
        VALUES(} . join(',', map '?', @columns) . q{)
end
else
begin
    update t_a set } . join(',' map { "$_ => ?" } @columns) . q{
end
};
my $sth = $dbi->prepare($sql);
foreach ($values = @{ $va_arr }) {
  $dbh->execute(@{$values}{@columns}, @{$values}{@columns});
}

如果您有一长串列并且您知道订单,请考虑以下事项:

@columns

让我们来看看它的作用。如果您有很长的列列表,这会很有帮助。

  • 您知道他们的姓名和顺序,并将其放入?
  • 根据这些列构建SQL。我们必须将列名称和INSERT添加到UPDATE,并将两者的组合添加到每个列的{{1}}。
  • 使用hash ref slice
  • 执行此操作

请注意,我没有运行此功能,只是在这里进行了黑客攻击。

答案 1 :(得分:0)

您应该将prepare语句放在循环之外并使用事务

例如:

my $sql1 = qq(select col_a from t_a where col_b = ?);
my $sql2 = qq(insert into t_a (col_a, col_b) VALUES(?, ?));
my $sql3 = qq(update t_a set col_a = ? where col_b = ?);

my $query = $dbh->prepare($sql1);

$dbh->begin_work();

foreach (@$va_arr) {

    my $values_for_one_row = $_;
    $query->execute($values_for_one_row->{col_b});
    my @out = $query->fetchrow_array();
    $query->finish();

    if ( not defined $out[0] )
      {
        $dbh->do($sql2, undef, $values_for_one_row->{col_a}, $values_for_one_row->{col_b});
      }
      else
      {
        $dbh->do($sql3, undef, $values_for_one_row->{col_a}, $values_for_one_row->{col_b});
      }
}

$dbh->commit();

答案 2 :(得分:0)

如果没有upsert,我可以这样做:

  1. 将数据批量加载到临时表中。

  2. 删除所有加入目标表的数据。

  3. 将数据从分段插入目标。

  4. 或者,您可以从登台更新到目标,从连接的登台数据中删除,然后插入暂存中的内容。

    或者,几百行并不多,所以我可能:在循环之外准备一个insert和一个update语句句柄。然后在循环中:

    my $rows = $upd_sth->execute(...);
    $ins_sth->execute(...) if $rows == 0;