2009-08-20 4 views
5

SQL SELECT 문에 의해 반환 된 행에 루프가 있으며 행 데이터에 대한 일부 처리 후에 때때로 행의 값을 업데이트하려고합니다. 루프의 본문에서 처리하는 것은 간단하지 않으며 SQL로 작성할 수 없습니다. 선택한 행에 대한 UPDATE를 실행하려고하면 오류가 발생합니다 (Perl의 DBD :: SQLite :: st 실행 실패 : 데이터베이스 테이블이 잠김). 할 일을 성취 할 수있는 읽기 쉽고 효율적이며 이식 가능한 방법이 있습니까? DBD 나 SQLite에 특화된 방법이 있습니까?루프에서 SELECT에 의해 반환 된 행을 어떻게 업데이트 할 수 있습니까?

분명히 별도의 데이터 구조로 업데이트를 푸시하고 루프 이후에 업데이트를 실행할 수 있지만 그 후에 코드의 모습을 싫어할 것입니다.

관심있는 사람은 여기에 해당하는 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; 
} 
+0

당신이 사용하는 perl이 너무 좋지 않을 때, Hibernate는 당신이하고 싶은 일에 완벽 할 것입니다. – Zoidberg

+2

내부적으로는 피하려고하는 비효율적 인 작업을 수행합니다. –

+6

@Zoidberg, 우리는 쓸데없는 말을 줄이지도 못한다. – friedo

답변

6

일시적으로 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; 
     } 
    } 
} 

을 코드가 실행 된 후 :

Zoidberg의 코멘트에 있지만은 전환 할 수 있다면 대답
 
sqlite> .header on 
sqlite> select * from test; 
field 
1 
two 
2

더 Perl의 DBIx::Class과 같은 ORM에 당신은 cou 이 같은 LD 쓰기 무언가 :

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 :: 클래스 Fey::ORM 같은 CPAN 예를 들면 Rose::DB에 대한 몇 가지 다른 사람들이 거기에 당신의 공상을 잡아하지 않는 경우.

2

페치 루프 중에 동일한 데이터베이스 처리기를 사용하여 업데이트를 수행하고 있다는 문제가 있습니다.

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

그런 다음 루프에서 dbhForUpdate를 사용하십시오 : 어쨌든

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

, 나는 좋은 거기 때문에이 일을 권하고 싶지 않다

그래서 업데이트를 수행하려면 데이터베이스 핸들러의 또 다른 인스턴스가 데이터베이스 수준에서 동시성 문제가 발생할 가능성이 있습니다.