2009-08-20 11 views
5

Tengo un bucle en las filas devueltas por una instrucción SQL SELECT y, después de algún procesamiento en los datos de una fila, a veces quiero ACTUALIZAR el valor de la fila. El procesamiento en el cuerpo del bucle no es trivial, y no puedo escribirlo en SQL. Cuando intento ejecutar UPDATE para la fila seleccionada, aparece un error (en DBD :: SQLite :: st ejecución de Perl fallaron: la tabla de la base de datos está bloqueada). ¿Hay una forma legible, eficiente y portátil de lograr lo que estoy tratando de hacer? En su defecto, ¿existe una forma específica DBD o SQLite para hacerlo?¿Cómo puedo ACTUALIZAR las filas devueltas por un SELECT en un bucle?

Obviamente, puedo insertar las actualizaciones en una estructura de datos separada y ejecutarlas después del ciclo, pero odiaría el aspecto del código.

Si te interesa, aquí tienes el código Perl correspondiente.

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

Lástima que el uso de Perl, Hibernate sería perfecto para lo que quiere hacer. – Zoidberg

+2

Internamente, realizaría la operación ineficiente que trato de evitar. –

+6

@Zoidberg, lástima que no podemos menospreciar los comentarios inútiles. – friedo

Respuesta

6

Activar temporalmente 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; 
     } 
    } 
} 

Después de que el código se ha ejecutado:

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

Más en respuesta a comentario de Zoidberg pero si su eran capaces de cambiar a un ORM como Perl's DBIx::Class, entonces usted encuentra que usted puede LD escribir algo como esto:

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

Y si DBIx :: Clase no ase su fantasía hay algunos otros en CPAN como Fey::ORM y Rose::DB por ejemplo.

2

Su problema es que está utilizando el mismo manejador de base de datos para realizar una actualización mientras se encuentra en un bucle de búsqueda.

Así tener otra instancia de su manejador de base de datos para realizar las actualizaciones:

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

A continuación, utilice dbhForUpdate en su bucle:

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

De todos modos, yo no recomendaría hacer esto ya que no es bueno es probable que se encuentre con problemas de concurrencia en el nivel de la base de datos.

Cuestiones relacionadas