如何更新循环中 SELECT 返回的行?
我对 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;
}
I have a loop on the rows returned by an SQL SELECT statement, and, after some processing on a row's data, I sometimes want to UPDATE the row's value. The processing in the loop's body is non-trivial, and I can't write it in SQL. When I try to execute the UPDATE for the selected row I get an error (under Perl's DBD::SQLite::st execute failed: database table is locked). Is there a readable, efficient, and portable way to achieve what I'm trying to do? Failing that, is there a DBD or SQLite-specific way to do it?
Obviously, I can push the updates in separate data structure and execute them after the loop, but I'd hate the code's look after that.
If you're interested, here is the corresponding Perl code.
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
暂时启用
AutoCommit
:代码运行后:
Temporarily enable
AutoCommit
:After the code has been run:
您的问题是,当您处于获取循环时,您使用相同的数据库处理程序来执行更新。
因此,让数据库处理程序的另一个实例来执行更新:
然后在循环中使用 dbhForUpdate:
无论如何,我不建议这样做,因为您很有可能在数据库级别遇到并发问题。
Your problem is that you're using the same database handler to perform an update while you're in a fetching loop.
So have another instance of your database handler to perform the updates:
Then use dbhForUpdate in your loop:
Anyway, I wouldn't recommend doing this since there's good chances you run into concurrency issues at the database level.
更多内容是对 Zoidberg 的评论的回答,但是如果您能够切换到像 Perl 那样的 ORM DBIx::Class 然后你发现你可以写这样的东西:
如果 DBIx::Class 没有吸引你的兴趣,那么 CPAN 就像Fey:例如 :ORM 和 Rose::DB 。
More in answer to Zoidberg's comment but if your were able to switch to an ORM like Perl's DBIx::Class then you find that you could write something like this:
And if DBIx::Class doesn't grab your fancy there are a few others on CPAN like Fey::ORM and Rose::DB for example.