2009-08-20 14 views
5

Tôi có một vòng lặp trên các hàng được trả về bởi một câu lệnh SQL SELECT, và sau một số xử lý trên dữ liệu của một hàng, đôi khi tôi muốn cập nhật giá trị của hàng. Việc xử lý trong cơ thể của vòng lặp là không tầm thường, và tôi không thể viết nó trong SQL. Khi tôi cố gắng thực thi UPDATE cho hàng đã chọn, tôi nhận được một lỗi (theo DBL :: SQLite :: st thực thi của Perl không thành công: bảng cơ sở dữ liệu bị khóa). Có cách nào có thể đọc được, hiệu quả và di động để đạt được những gì tôi đang cố gắng làm không? Nếu không, có một cách cụ thể DBD hoặc SQLite để làm điều đó?Làm thế nào tôi có thể CẬP NHẬT hàng trả về bởi một SELECT trong một vòng lặp?

Rõ ràng, tôi có thể đẩy các bản cập nhật trong cấu trúc dữ liệu riêng biệt và thực thi chúng sau vòng lặp, nhưng tôi sẽ ghét cái nhìn của mã sau đó.

Nếu bạn quan tâm, đây là mã Perl tương ứng.

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; 
} 
+0

Quá xấu khi sử dụng perl của bạn, Hibernate sẽ là hoàn hảo cho những gì bạn muốn làm. – Zoidberg

+2

Một nội bộ nó sẽ thực hiện các hoạt động không hiệu quả Tôi đang cố gắng để tránh. –

+6

@Zoidberg, quá tệ, chúng tôi không thể giảm bớt những nhận xét vô ích. – friedo

Trả lời

6

Tạm thời cho phép AutoCommit:

 
sqlite> .header on 
sqlite> select * from test; 
field 
one 
two 
#!/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; 
     } 
    } 
} 

Sau khi mã đã được chạy:

 
sqlite> .header on 
sqlite> select * from test; 
field 
1 
two 
2

khác ở câu trả lời cho Zoidberg của bình luận nhưng nếu bạn có thể chuyển đổi với ORM như số DBIx::Class của Perl thì bạn thấy rằng bạn ld viết một cái gì đó như thế này:

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 }); 
    } 
} 

Và nếu DBIx :: Class không lấy ưa thích của bạn có một vài người khác trên CPAN như Fey::ORMRose::DB ví dụ.

2

Vấn đề của bạn là bạn đang sử dụng cùng một trình xử lý cơ sở dữ liệu để thực hiện cập nhật trong khi bạn đang trong vòng lặp tìm nạp.

Vì vậy, có một thể hiện của bộ xử lý cơ sở dữ liệu của bạn để thực hiện các bản cập nhật:

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

Sau đó sử dụng dbhForUpdate trong vòng lặp của bạn:

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

Dù sao, tôi sẽ không khuyên bạn làm điều này vì không tốt cơ hội bạn chạy vào các vấn đề tương tranh ở cấp cơ sở dữ liệu.