5

我对 SQL SELECT 语句返回的行有一个循环,并且在对行的数据进行一些处理之后,我有时想更新行的值。循环体中的处理非常重要,我不能用 SQL 编写它。当我尝试对所选行执行 UPDATE 时,出现错误(在 Perl 的 DBD::SQLite::st 下执行失败:数据库表已锁定)。是否有一种可读、高效且可移植的方式来实现我想要做的事情?如果做不到这一点,是否有 DBD 或 SQLite 特定的方法来做到这一点?

显然,我可以在单独的数据结构中推送更新并在循环后执行它们,但我讨厌代码的照顾。

如果你有兴趣,这里是对应的 Perl 代码。

my $q = $dbh->prepare(q{
  SELECT id, confLoc FROM Confs WHERE confLocId ISNULL});
$q->execute or die;
my $u = $dbh->prepare(q{
  UPDATE Confs SET confLocId = ? WHERE id = ?});
while (my $r = $q->fetchrow_hashref) {
    next unless ($r->{confLoc} =~ m/something-hairy/);
    next unless ($locId = unique_name_state($1, $2));
    $u->execute($locId, $r->{id}) or die;
}
4

3 回答 3

6

暂时启用AutoCommit

sqlite> .header on
sqlite> 从测试中选择 *;
场地
一
二
#!/usr/bin/perl

use strict;
use warnings;

use DBI;

my $dbh = DBI->connect('dbi:SQLite:test.db', undef, undef,
    { RaiseError => 1, AutoCommit => 0}
);

test_select_with_update($dbh);

sub test_select_with_update {
    my ($dbh) = @_;
    local $dbh->{AutoCommit} = 1;
    my $q = $dbh->prepare(q{SELECT field FROM test});
    my $u = $dbh->prepare(q{UPDATE test SET field = ? WHERE field = ?});
    $q->execute or die;
    while ( my $r = $q->fetchrow_hashref ) {
        if ( (my $f = $r->{field}) eq 'one') {
            $u->execute('1', $f) or die;
        }
    }
}

代码运行后:

sqlite> .header on
sqlite> 从测试中选择 *;
场地
1
二
于 2009-08-20T13:27:35.353 回答
2

更多地回答 Zoidberg 的评论,但如果你能够切换到像 Perl 的DBIx::Class这样的 ORM ,那么你会发现你可以写这样的东西:

my $rs = $schema->resultset('Confs')->search({ confLocId => undef });

while ( my $data = $rs->next ) {
    next unless $data->confLoc =~ m/(something)-(hairy)/;
    if ( my $locId = unique_name_state( $1, $2 ) ) {
        $data->update({ confLocID => $locid });
    }
}

如果 DBIx::Class 没有引起您的兴趣,那么CPAN上还有其他一些,例如Fey::ORMRose::DB

于 2009-08-20T16:45:28.657 回答
2

您的问题是您在获取循环中使用相同的数据库处理程序来执行更新。

因此,让您的数据库处理程序的另一个实例来执行更新:

my $dbh = DBI->connect(...);
my $dbhForUpdate = DBI->connect(...) ;

然后在循环中使用 dbhForUpdate:

while(my $row = $sth->fetch()){
   ...
   $dbhForUpdate->do(...) ;
}

无论如何,我不建议这样做,因为您很有可能在数据库级别遇到并发问题。

于 2009-08-20T19:39:15.997 回答