perl script, accessing mysql, check if 3 fields combined already exist
I have this following Perl script, i would like it to check if the name, level, and area fields are, combined, a unique reference. If there is already an entry fitting those fields, ignore it and do nothing. If there isn't an entry with these specifications, add it.
This one works, but doesn't check if there is an unique entry already and adds without consideration
#! /usr/bin/perl -w
use DBI;
use DBD::mysql;
use Data::Dumper;
# MySQL Variables
my ($username, $password, $db, $login_info);
$username=""; #omitted
$password=""; #omitted
$db=''; #omitted
$table=''; #omitted
$dbh=DBI->connect("dbi:mysql:$db", $username, $password) or die "Connecti开发者_开发技巧on Error: $DBI::errstr\n";
my $insert=$dbh->do("INSERT INTO $table (area, name, level, align, hp, maxhp, bash, pierce, slash, acid, air, cold, disease, earth, fire, holy, light, electric, magic, mental, negative, poison, shadow, sonic, water) VALUES ('$ARGV[0]', '$ARGV[1]', '$ARGV[2]', '$ARGV[3]', '$ARGV[4]', '$ARGV[5]', '$ARGV[6]', '$ARGV[7]', '$ARGV[8]', '$ARGV[9]', '$ARGV[10]', '$ARGV[11]', '$ARGV[12]', '$ARGV[13]', '$ARGV[14]', '$ARGV[15]', '$ARGV[16]', '$ARGV[17]', '$ARGV[18]', '$ARGV[19]', '$ARGV[20]', '$ARGV[21]', '$ARGV[22]', '$ARGV[23]', '$ARGV[24]');");
The following was my attempt to make it check, which failed miserably. Any and all help would be appreciated.
#! /usr/bin/perl -w
use DBI;
#! /usr/bin/perl -w
use DBI;
use DBD::mysql;
use Data::Dumper;
# MySQL Variables
my ($username, $password, $db, $login_info);
$username=""; #omitted
$password=""; #omitted
$db=''; #omitted
$table=''; #omitted
$dbh=DBI->connect("dbi:mysql:$db", $username, $password) or die "Connection Error: $DBI::errstr\n";
my ($area, $name, $level) = ($ARGV[1], $ARGV[1], $ARGV[2]);
my $query=$dbh->prepare("SELECT name, area, level from Interrogate WHERE name=$name, area=$area, level=$level;");
$do=$query->execute( );
if ($do) {
my $insert=$dbh->do("INSERT INTO $table (area, name, level, align, hp, maxhp, bash, pierce, slash, acid, air, cold, disease, earth, fire, holy, light, electric, magic, mental, negative, poison, shadow, sonic, water) VALUES ('$ARGV[0]', '$ARGV[1]', '$ARGV[2]', '$ARGV[3]', '$ARGV[4]', '$ARGV[5]', '$ARGV[6]', '$ARGV[7]', '$ARGV[8]', '$ARGV[9]', '$ARGV[10]', '$ARGV[11]', '$ARGV[12]', '$ARGV[13]', '$ARGV[14]', '$ARGV[15]', '$ARGV[16]', '$ARGV[17]', '$ARGV[18]', '$ARGV[19]', '$ARGV[20]', '$ARGV[21]', '$ARGV[22]', '$ARGV[23]', '$ARGV[24]');");
}
EDIT Removed extraneous curly brace.
You seem to be confused about what execute
returns, from the fine manual:
An
undef
is returned if an error occurs. A successful execute always returns true regardless of the number of rows affected, even if it's zero (see below).
[...]
The execute method does not return the number of rows that will be returned by the query (because most databases can't tell in advance), it simply returns a true value.
So you want to do something like this instead:
my $query = $dbh->prepare("SELECT COUNT(*) FROM Interrogate WHERE name = ? AND area = ? AND level = ?");
$query->execute($name, $area, $level);
my $count = $query->fetchrow_arrayref();
if(!$count->[0]) {
# do the insert
}
I threw in the placeholders (to protect against SQL injection attacks) and corrected the syntax of your WHERE clause for free.
Even better would be to put a unique index on (name,area,level) inside the database. Then you could just do the INSERT and trap and ignore the "unique constraint violated" exception. This approach protects against a race condition in your approach: you check for an existing row but don't find one, another process adds the row, you add the row but end up with a duplicate because someone else inserted it between your check and your insert. Pushing data integrity issues down into the database is always your best bet, databases are good at things like that.
instead of if ($do)
shouldn't you check the number returned (something like this)? And try this sql statement instead SELECT name, area, level from Interrogate WHERE name=$name AND area=$area AND level=$level;
(use AND in the where clause)
精彩评论