Reputation: 93
Can someone help me figure out the correct syntax of
for (my $i = 0; $i <=3; $i++)
{
$store = qq(INSERT INTO main (creator_name,relationship)
VALUES("$data{creatorname}",$data{"relationship$i"}) );
The problem lies with $data{"relationship$1"}. I'm looping because I have 'relationship1', 'relationship2', and 'relationship3' in my data hash. I didn't want to go through 3 separate mysql queries to get the job done so I'm trying to loop over it.
Any pointers?
EDIT:
Thanks for your help with pointing me towards placeholders. It's not working as placeholders and it looks like it's because of
$sth->execute($data{creatorname},$data{relationship},"DATE_ADD(NOW(), INTERVAL $interval)"
I have a DATE_ADD now that I'm using, it doesn't look like it likes to be used as a placeholder.
Upvotes: 0
Views: 193
Reputation: 58524
It's a bit hard on the eyes, but if you always have three rows to enter you could do it all in one execute()
:
my $sth = $dbh->prepare(<<'__eosql');
INSERT INTO main (time_column, creator_name, relationship)
SELECT NOW() + INTERVAL ? HOUR, -- placeholder for $interval
?, -- $data{creatorname}
relation
FROM (SELECT ? AS relation -- $data{relationship1}
UNION ALL
SELECT ? -- $data{relationship2}
UNION ALL
SELECT ?) d -- $data{relationship3}
__eosql
$sth->execute($interval, @data{qw(creatorname relationship1 relationship2 relationship3)});
That uses a hash slice to pull the values out of %data
.
Upvotes: 0
Reputation: 562230
As @mob says, you should use query parameters instead of fighting with how to interpolate variables directly into strings.
$store = qq(INSERT INTO main (creator_name, relationship) VALUES (?, ?));
$st = $dbi->prepare($store);
for (my $i = 0; $i < 3; $i++)
{
$st->execute($data{creatorname}, $data{"relationship$i"});
}
Advantages of using parameters:
Re your comment:
An SQL parameter can be used only in place of a single scalar value. Not an expression, or a table name or column name, or a list of values, or SQL keywords. Basically, any value you pass for the parameter value will be treated as though you had put quotes around it (there are some nuances to that, but it gives you the approximate idea).
Given the expression you described, I'd write the code like this:
$store = qq(INSERT INTO main (creator_name, relationship, complicated_column)
VALUES (?, ?, DATE_ADD(NOW(), INTERVAL ? HOUR)));
$st = $dbi->prepare($store);
for (my $i = 0; $i < 3; $i++)
{
$st->execute($data{creatorname}, $data{"relationship$i"}, $interval);
}
Re answer from @harmic:
This is awkward to reply to another answer by adding to my own answer, but I wanted to share a code test that demonstrates the "double-interpolation" does in fact work.
$ cat test.pl
$i = 1;
$data{"key$i"} = "word";
$s = qq(string with parentheses ($data{"key$i"}));
print $s, "\n";
$ perl test.pl
string with parentheses (word)
The output of running this Perl script shows that the interpolation worked.
Upvotes: 1
Reputation: 30577
As pointed out by mob and Bill, if possible it is best to use place holders, but that's not the reason your code is not working.
It is not working because you are trying to do two levels of variable interpolation in one string: first interpolate $i into "relationship$i", then interpolate $data{"relationship$i"} into the larger string quoted with qq. They will not nest like that.
This would work:
for (my $i = 0; $i <=3; $i++)
{
my $relationship = $data{"relationship$i"}
$store = qq(INSERT INTO main (creator_name,relationship)
VALUES("$data{creatorname}",$relationship ) );
Upvotes: 1