如何使用不同数量的参数为DBI更新编写子例程?

时间:2009-02-17 15:32:02

标签: perl dbi

我正在为DBI更新编写子程序,并且在确定如何添加占位符和内容方面遇到一些麻烦......

我有这个:

sub row_update {
  my $table = shift;
  my %updates = @_;
  my $placeholders = ...

  $dbh->do("UPDATE $table SET (foo) WHERE (bar)") etc...
}

有什么想法吗?

我只想要一个简单的更新函数,我可以在其中发送x个参数(作为哈希)。

提前致谢!

4 个答案:

答案 0 :(得分:4)

这样的事情可能足够好了:

sub update {
    my ($dbh, $args) = @_;

    my $table   = $args->{table}   || die 'need table';
    my $updates = $args->{updates} || die 'need updates';

    my @cols = keys %$updates;

    my $query = 'UPDATE $table SET '.
      (join ', ', map { '$_ = ?' } @cols)
      ($args->{where} ? ' WHERE '. $args->{where} : '');

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

    $sth->execute(map { $updates->{$_} } @cols);

    return $sth;
}

使用它像:

my $sth = update $dbh, {
    table   => 'foo',
    updates => {
        col1 => 'new_value',
        col2 => 'another_value',
    },
    where => 'id=42',
};

但是,你真的想要使用类似的ORM DBIx::Class。它可以更好地构建查询 像这样的字符串操作会。

(重写要参数化的where子句留给读者练习。你还需要引用更新密钥和表名。看看为什么人们使用ORM?)

编辑:考虑到这一点,您可能希望DBIx::SimpleSQL::Abstract结合使用。这将比ORM花费更少的配置工作,但仍然为您提供许多好处。

答案 1 :(得分:3)

如果我正确理解了这个问题,听起来好像是在SQL::Abstract之后。首先,我们创建一个SQL::Abstract对象:

use SQL::Abstract;
my $sql = SQL::Abstract->new;

现在,作为一个例子,我们将使用它将一些数据插入表中:

my %record = (
    FirstName  => 'Buffy',
    LastName   => 'Summers',
    Address    => '1630 Revello Drive',
    City       => 'Sunnydale',
    State      => 'California',
    Occupation => 'Student',
    Health     => 'Alive',
);

my ($stmt, @bind) = $sql->insert(’staff’,\%record);

这导致:

$stmt = "INSERT INTO staff
                (FirstName, LastName, Address, City,
                 State, Occupation, Health)
                 VALUES (?, ?, ?, ?, ?, ?, ?)";

@bind = ('Buffy','Summers','1630 Revello Drive',
         'Sunnydale',’California','Student','Alive');

关于这个的好处是我们可以直接将它传递给DBI:

 $dbh->do($stmt, undef, @bind);

当然,您希望更新记录,而不仅仅是插入记录。幸运的是,这也很容易:

my $table = 'People';

my %new_fields = (
    Occupation => 'Slayer',
    Health     => 'Dead',
);

my %where = (
    FirstName => 'Buffy',
    LastName  => 'Summers',
);

my ($stmt, @bind) = $sql->update($table, \%new_fields, \%where);

$dbh->do($stmt, undef, @bind);

这会产生:

$stmt = 'UPDATE People SET Health = ?, Occupation = ? 
         WHERE ( FirstName = ? AND LastName = ? )';

@bind = ('Dead', 'Slayer', 'Buffy', 'Summers');

如果您要了解有关SQL::Abstract的更多信息,建议您查看其CPAN page。在Perl Training Australia使用Perl进行数据库编程手册中还有一章可以从course notes page免费获得。

一切顺利,

免责声明:我是Perl Training Australia的常务董事,因此我认为我们的课程笔记非常好。

答案 2 :(得分:1)

其他人建议通常“使用正确数量的”?“方法构建查询。

对于像这样的大多数查询,忘记了DBI-> quote方法,但它可以使代码更简单,并且在大多数情况下它并不比“适当的”占位符方法慢。

1)使用DBI->引号而不是占位符来构建查询。例如,对于简单的选择:

my $sql = "select foo from bar where baz in ("
           . join(",", map { DBI->quote($_) } @bazs)
           . ")";
my $data = $dbh->selectall_arrayref($sql);

2)正如jrockway建议的那样 - 使用ORM为你做这种低级别的东西。例如,DBIx :: Class或Rose :: DB :: Object。

答案 3 :(得分:0)

NUM_OF_PARAMS属性可能有所帮助:

"NUM_OF_PARAMS"  (integer, read-only)
     The number of parameters (placeholders) in the prepared
     statement.

例如,我有一个脚本可以从使用此代码的命令行运行任意SQL:

my $s = $h->prepare($_);

for my $i (1..$s->{NUM_OF_PARAMS}){
  my $param = shift @ARGV;
  $s->bind_param($i, $param);
  print LOG "Bind param $i using $param.\n"
    or die "can't append to $opt{log}: $!";
}

$s->execute();

我不能说我已经使用了其他建议的模块,所以他们可以做得更好。