Advice or best practice for updating multiple rows with a single query
[email protected] (Ritter) Mon, 28 Aug 2023 08:57:51 +0200
| Newsgroups | perl.dbi.users |
|---|---|
| Message-ID | <[email protected]> |
Dear Mongers,
here is my example code trying to update multiple rows with a single =
query. Since the number of lines to be updated varies constantly, both =
the placeholders and the data need to be generated dynamically with each =
call.
=09
Based on the following example =
(https://www.geeksengine.com/database/data-manipulation/update-multiple-ro=
ws-one-query-part1.php) I tried to map it with the following code.
=
=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=
=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=
=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=
=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94 =
code =
=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=
=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=
=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=
=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=20=
#!/usr/bin/perl
use strict;
use warnings;
use feature qw(say);
use DBI();
use Data::Dumper;
use Data::Printer {
color =3D> {
'regex' =3D> 'yellow',
'hash' =3D> 'blue',
'string' =3D> 'cyan',
'array' =3D> 'green'
},
};
my $href =3D {
FOO =3D> {
Company =3D> "Foo Ltd.",
fw_id =3D> 11111,
cust_id =3D> 1001,
vpn_pri_ipv4 =3D> "192.168.1.1",
vpn_sec_ipv4 =3D> undef
},
BAR =3D> {
Company =3D> "Bar Ltd.",
fw_id =3D> 22222,
cust_id =3D> 1234,
vpn_pri_ipv4 =3D> "172.16.1.1",
vpn_sec_ipv4 =3D> undef
},
BAZ =3D> {
Company =3D> "Baz Ltd.",
fw_id =3D> 33333,
cust_id =3D> 4321,
vpn_pri_ipv4 =3D> "10.1.1.1",
vpn_sec_ipv4 =3D> undef
}
};
#delete $href->{BAZ};
#delete @{$href}{'BAR', 'BAZ'};
#delete @{$href}{qw/BAR BAZ/};
db_update_with_fw_obj_ids($href);=20
sub db_update_with_fw_obj_ids {
=20
my $data =3D shift;
my $db_values_to_be_updated;
foreach (keys %{$data}) {
$db_values_to_be_updated->{$data->{$_}{cust_id}} =3D =
$data->{$_}{fw_id};
};
=20
my $when_clause =3D join"\n\t", map { "when ? then ?" } (keys =
%{$db_values_to_be_updated});
my @placeholders =3D ( join',', ('?') x (keys =
%{$db_values_to_be_updated}));
print "\nWhen-clause for \$dbh->prepare(\$sql): \n", $when_clause, =
"\n";
print "#"x80, "\n";
print "\nPlaceholders for \$dbh->prepare(\$sql): ", @placeholders, =
"\n";
print "#"x80, "\n";
my $example =3D "
UPDATE condats SET=20
fw_obj_id =3D=20
CASE condats.cust_id
when '1001' then '111111'
when '1234' then '222222'
when '4321' then '333333'
ELSE fw_obj_id
END
WHERE condats.cust_id IN ('1001','1234','4321');
";
=20
my $dbh =3D =
DBI->connect("DBI:mysql:database=3Ddev;host=3D192.168.200.100","User","Pas=
sword",{'RaiseError' =3D> 1});
$dbh->do("set character set latin1");
$dbh->do("set names latin1");
my $sql =3D <<"EOF_INPUT";
UPDATE condats SET=20
fw_obj_id =3D=20
CASE condats.cust_id
$when_clause
ELSE fw_obj_id
END
WHERE condats.cust_id IN (@placeholders);
EOF_INPUT
print "\n", "#"x30, " SQL query with example data ", "#"x30, "\n";
p $example;
print "#"x28, " SQL query with dbi placeholders ", "#"x28, "\n";
p $sql;
print "#"x125, "\n";
my @x =3D map { $_, $db_values_to_be_updated->{$_} } keys =
%{$db_values_to_be_updated};=20
print "(1st) data set passed as 'map { \$_, =
\$db_values_to_be_updated->{\$_} } keys \%{\$db_values_to_be_updated}' =
to \$sth->execute():\n", Dumper(\@x);=20
print "#"x125, "\n";
my @y =3D (keys %{$db_values_to_be_updated});
print "(2nd) data set passed as 'keys \%{\$db_values_to_be_updated}' =
to \$sth->execute():\n", Dumper(\@y);
my $sth =3D $dbh->prepare($sql);
$sth->execute((map { $_, $db_values_to_be_updated->{$_} } (keys =
%{$db_values_to_be_updated})), keys %{$db_values_to_be_updated}) or die =
$DBI::errstr;
print "Number of rows updated :", $sth->rows, "\n";
$sth->finish();
$dbh->disconnect();
}
=
=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=
=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=
=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=
=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=
=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=
=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=
=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=
=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=
=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94
What I don't like is the awkward way of dynamically creating the =
placeholders for "$sth =3D $dbh->prepare($sql)" and how the data is =
passed to $sth->execute(). There is one part =E2=80=9Efeeding" the =
values for CASE and another part =E2=80=9Efeeding=E2=80=9C the values =
for "WHERE condats.cust_id IN ('1001','1234','4321=E2=80=99)=E2=80=9C.
Possibly only a "smarter" data structure is needed, from which DBI on =
the one hand takes the data for the CASE part and from another part of =
the data structure data for the WHERE clause?
I wonder if there is a smarter way to create the DBI-placeholder and how =
to hand over the data to $sth->execute() in one shot.
Any recommendations/best practices?
Any advice would be be highly appreciated.
Cheers,
Ritter=