3

我正在为 DBI 更新编写一个子例程,并且在弄清楚如何添加占位符和东西时遇到了一些麻烦......

我有这个:

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

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

有任何想法吗?

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

提前致谢!

4

4 回答 4

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',
};

但实际上,您想研究使用像 DBIx::Class这样的 ORM 。与这样的字符串操作相比,它在构建查询方面做得更好。

(重写要参数化的 where 子句作为练习留给读者。您还需要引用更新键和表名。了解人们为什么使用 ORM 吗?)

编辑:再考虑一下,您可能会喜欢DBIx::SimpleSQL::Abstract的结合。与 ORM 相比,这将花费更少的配置工作,但仍会给您带来许多好处。

于 2009-02-17T17:20:11.517 回答
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 页面Perl Training AustraliaDatabase Programming with Perl手册中还有一章,可从我们的课程笔记页面免费获得。

祝一切顺利,

保罗

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

于 2009-02-17T21:53:22.683 回答
1

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

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

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

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。

于 2009-02-18T00:10:39.593 回答
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();

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

于 2009-02-17T23:15:53.797 回答