Updating lots of database fields in a single row

Abigail abigail at abigail.be
Wed Jan 23 10:16:36 GMT 2013


On Tue, Jan 22, 2013 at 10:57:29PM +0000, Andrew Beverley wrote:
> I've not been developing with Perl for long, so I'd like to know if
> there is a better way of writing the following database query (or is
> there a better place to ask?):
> 
> 
> my @fields = qw(field1 field2 field3 field4 field5 field6 field7 ... );
> my @updates;
> foreach my $field (@fields)
> {
>     push @updates, "$field = '$hash->{$field}'" if $hash->{$field};
> }
> my $values = join ',', @updates;
> my $sth = $self->dbh->prepare("UPDATE table SET $values WHERE id = ?");
> $sth->execute($opdefs_id);
> 
> 
> Basically, I'd like to update lots of fields in a single database row.
> Obviously I could write out each updated field individually, but I
> wondered whether the above is considered tidier, or whether there is a
> better way altogether? The problem with the above code is that I'm not
> using placeholders and bind values (which I assume is to be preferred)
> so I'll also need to escape values as required.
> 


I'd write something like (untested):

my @fields = grep {$$hash {$_}} qw [field1 field2 field3 ...];
if (@fields) {
    my $query = do {local $" = ", ", <<"    --"};
    UPDATE  table
       SET  @{[map {"$_ = ?"} @fields]}
     WHERE  id = ?
    --
    my $dbh = $sth -> dbh;
    eval {
        local $dbh -> {AutoCommit} = 0;
        local $dbh -> {RaiseError} = 1;
        local $dbh -> {PrintError} = 0;
        my $sth = $dbh -> prepare ($query);
        $sth -> execute (@{$hash} {@fields}, $opdefs_id);
        $dbh -> commit;
        1;
    }
    or do {
        my $error = $@;
        eval {
            $dbh -> rollback;
            1;
        } or die "Rollback failed: $@ (after error: $error)\n";
        die $error, "\n";
    }
}


Abigail


More information about the london.pm mailing list