I'm trying to execute the following script:
#!/usr/bin/perl -w
use strict;
use DBI;
my $db = "Pg";
my $db_database = "whatever";
my $user = "whatever";
my $password = "whatever";
my $dbh = DBI->connect("dbi:$db:dbname=$db_database", $user, $password);
my $query = $dbh->prepare (q{SELECT
arrival_date - INTERVAL '? MINUTE'
FROM emails LIMIT 1})
or die ("unable to prepare");
$query->execute(60) or die("unable to execute");
print $query->fetchrow_array, "\n";
(arrival_date has this format: timestamp with time zone NOT NULL default CURRENT_TIMESTAMP)
The problem is that the question mark placeholder is not detected because its inside single quotes:
DBD::Pg::st execute failed: called with 1 bind variables when 0 are needed
It does not help if I use qq{}, $1 placeholder, and tried a few variations with $dbh->quote. How can I make this work?
You can't use placeholders inside quotes. You can use SQL string concatenation, but in this case, it's easier to do it by using multiplication:
my $query = $dbh->prepare (q{SELECT
arrival_date - ? * INTERVAL '1 MINUTE'
FROM emails LIMIT 1});
$query->execute(60);
That way, you don't have to append ' minutes' to the number when you execute the query.
I just found a solution here: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=321917
It works using ?::interval instead of 'interval ?':
my $query = $dbh->prepare (q{SELECT
arrival_date - ?::interval
FROM emails LIMIT 1});
$query->execute('60 MINUTE');
my $query = $dbh->prepare (<<SQL) or die ("unable to prepare");
SELECT arrival_date - INTERVAL ? FROM emails LIMIT 1
SQL
$query->execute("60 MINUTE");
or
my $query = $dbh->prepare (<<SQL) or die ("unable to prepare");
SELECT arrival_date - INTERVAL CONCAT(?, " MINUTE") FROM emails LIMIT 1
SQL
$query->execute(60);
Related
i am getting below error while running below perl script. Can anybody help to figure it out?
$ENV{PATH}= '/appl/OMS/scripts:/etc:/usr/bin:/usr/sbin:/b...';
$ENV{PATH}= '/appl/OMS/scripts:/etc:/usr/bin:/usr/sbin:/bin:/usr/local/bin:/usr/local/opt/oracle/client/11.2.0.4/bin';
$ENV{ORACLE_HOME} ='/usr/local/opt/oracle/client/11.2.0.4';
$ENV{NLSPATH} = '/usr/lib/nls/msg/%L/%N:/usr/lib/nls/msg/%L/%N.cat';
$ENV{CLASSPATH} = 'CLASSPATH=/usr/local/opt/oracle/client/11.2.0.4/jdbc/lib';
$ENV{JAVA_HOME} = '/appl/OMS/Software/java';
$ENV{PERL5LIB} = '/appl/OMS/perl/lib';
use lib "/appl/OMS/perl/lib";
}
use DBI;
use DBD::Oracle;
use Data::Dumper;
use POSIX qw/strftime/;
use Switch;
use Term::ANSIColor;
print " Input the environment name:\n";
chomp($env=<STDIN>);
print " Input attuid:\n";
chomp($attuid=<STDIN>);
print " Input first name:\n";
chomp($fname = <STDIN>);
print " Input last name:\n";
chomp($lname= <STDIN>);
#chomp($lname);
my $dbInst="t1oms4d8.db.att.com";
my $dbUser="OMS1AT01utils";
my $dbPass="pswd4conn";
my $host = "t1oms5c1.sldc.sbc.com";
#$dsn= "dbi:oracle:T2OMS1D4.db.att.com:t2oms1c1.hydc.sbc.com:1521";
#$DBIconnect= DBI->connect($dsn,OMS0BT08utils,Pwd0wner1);
my $dbh=DBI->connect("dbi:Oracle:$dbInst", $dbUser, $dbPass);
my $sth = $dbh->prepare('create table temp_table1 as (select * from users where user_id like '%SR508W%')');
$sth-> execute();
print "test1";
my $sth = $dbh->prepare("update temp_table1 set user_id= ".$attuid.", first_nm= ".$fname.", last_nm= ".$lname." where user_id like '%SR508W%' " );
$sth-> execute();
print "test2";
my $sth = $dbh->prepare("insert into users (select * from temp_table1)");
$sth-> execute();
my $sth = $dbh->prepare("insert into user_password(user_id,password1) values (".$attuid." ,(select PASSWORD1 FROM user_password where user_id like '%SR508W%'))");
$sth-> execute();
my $sth = $dbh->prepare("insert into user_role(user_id,role_id) values (".$attuid." ,'1')");
$sth-> execute();
my $sth = $dbh->prepare("select * from temp_table1");
$sth-> execute();
my $sth = $dbh->prepare("drop table temp_table1");
$sth->execute();
$sth->finish();
$dbh->commit or die $DBI::errstr;
I am running the script as below:
$ ./dbtrial.pl
Input the environment name:
oms1at01
Input attuid:
sm501u
Input first name:
swapnil
Input last name:
mahindrakar
The error message is the following:
DBD::Oracle::st execute failed: ORA-00904: "MAHINDRAKAR": invalid identifier (DBD ERROR: error possibly near <*> indicator at char 69 in 'update temp_table1 set user_id= sm501u, first_nm= swapnil, last_nm= <*>mahindrakar where user_id like '%SR508W%' ') [for Statement "update temp_table1 set user_id= sm501u, first_nm= swapnil, last_nm= mahindrakar where user_id like '%SR508W%' "] at ./dbtrial.pl line 45, <STDIN> line 4.
DBD::Oracle::st execute failed: ORA-00984: column not allowed here (DBD ERROR: error possibly near <*> indicator at char 53 in 'insert into user_password(user_id,password1) values (<*>sm501u ,(select PASSWORD1 FROM user_password where user_id like '%SR508W%'))') [for Statement "insert into user_password(user_id,password1) values (sm501u ,(select PASSWORD1 FROM user_password where user_id like '%SR508W%'))"] at ./dbtrial.pl line 50, <STDIN> line 4.
DBD::Oracle::st execute failed: ORA-00984: column not allowed here (DBD ERROR: error possibly near <*> indicator at char 47 in 'insert into user_role(user_id,role_id) values (<*>sm501u ,'1')') [for Statement "insert into user_role(user_id,role_id) values (sm501u ,'1')"] at ./dbtrial.pl line 52, <STDIN> line 4.
commit ineffective with AutoCommit enabled at ./dbtrial.pl line 58, <STDIN> line 4.
test1test2----- websphe cldv0011 /appl/OMS/scripts/trials ---
Apart from missing a #! /usr/bin/perl (or similar) line, the most obvious thing wrong with your script is that you're not properly quoting your variables when you use them in SQL statemnents.
The easiest way to fix that is to use placeholders (?) in your $dbh->prepare() statements. And then supply the actual values in the $sth-execute()
For example:
my $sth = $dbh->prepare("update temp_table1 set user_id=?,
first_nm=?, last_nm=?
where user_id like '%SR508W%'");
$sth->execute($attuid,$fname,$lname);
This will automagically quote the variables that need quoting, which seems to be all of them for this example as they're all string values.
Also, you only have to define the scope of your variables once. You don't need to (and shouldn't) say my $sth= every time you set it to a new value. Either declare it separately before using it at all (with just my $sth;, or only declare it the very first time you use it.
And add a blank line or two to separate each different section of the script. That will make it MUCH easier to read than the ugly wall of text it is now.
Finally, you might want to consider taking the input from the command line. This will make testing much easier as you can use your shell's command-line history and recall features (i.e. hit up arrow and enter to execute the same command again) rather than having to enter the same four values into the script every time you run it. e.g.
# environment name is first arg
my $env = shift;
# attuid is second arg
my $attuid = shift;
# First name is third arg
my $fname = shift;
# Last name is fourth arg
my $lname = shift;
Run it like this:
$ ./dbtrial.pl oms1at01 sm501u swapnil mahindrakar
(Note: this is really primitive argument handling. Use Getopt::Std or Getopt::Long if you need something better than just taking the first four args from the command line).
Personally, I'd be inclined to rewrite your script to something more like this (with better formatting, removal of variables and modules that aren't used, better usage of DBI features, and improved sql string construction):
#! /usr/bin/perl
use strict;
use warnings;
use lib "/appl/OMS/perl/lib";
use DBI;
use DBD::Oracle;
my ($env,$attuid,$fname,$lname);
# environment name is first arg
$env = shift;
# attuid is second arg
$attuid = shift;
# First name is third arg
$fname = shift;
# Last name is fourth arg
$lname = shift;
my ($dbInst, $dbUser, $dbPass, $host, $dbh, $sth, $sql, $where);
$dbInst="t1oms4d8.db.att.com";
$dbUser="OMS1AT01utils";
$dbPass="pswd4conn";
$dbh=DBI->connect("dbi:Oracle:$dbInst",$dbUser,$dbPass);
$where=' where user_id like \'%SR508W%\'';
$dbh->do('create table temp_table1 as (select * from users ' . $where . ')');
print "test1";
$sql = 'update temp_table1 set user_id=?, first_nm=?, last_nm=?' . $where;
$sth = $dbh->prepare($sql);
$sth->execute($attuid,$fname,$lname);
print "test2";
$dbh->do('insert into users (select * from temp_table1)');
$sql = 'insert into user_password(user_id,password1) values (?,(select PASSWORD1 FROM user_password' . $where . ' ))';
$sth = $dbh->prepare($sql);
$sth->execute($attuid);
$sql = 'insert into user_role(user_id,role_id) values (?,?)';
$sth = $dbh->prepare($sql);
# does '1' need to be quoted here? if field is a varchar or similar then yes, otherwise no. assuming yes as in the original script.
$sth->execute($attuid,'1');
$dbh->do('select * from temp_table1');
$dbh->do('drop table temp_table1');
$sth->finish();
$dbh->commit or die $DBI::errstr;
$dbh->finish();
I am trying to run a select statement to a sqlite3 database using Perl DBI. The following is the code:
my $dbh = DBI->connect( "DBI:SQLite:dbname=./GenBankData.db" , "" , "" , { PrintError => 0 , RaiseError => 1 } );
my $Sql = 'select AccessionQueryResultID, AccessionNumber, Definition from AccessionQueryResult';
my $sth = $dbh->prepare( $Sql ) or die "Couldn't prepare statement: " . $dbh->errstr;;
$sth->execute( $Sql) or die "Couldn't execute statement: " . $dbh->errstr;
But I am getting the following error:
DBD::SQLite::st execute failed: called with 1 bind variables when 0 are needed at /home/mysite.cgi line 33
I have checked that the database and table exist and the same query works fine if I used the sqlite3 command line to run the query.
Thanks
$sth is a statement handle. It represents the SQL statement/query, so having to provide the SQL statement to the object again makes no sense.
The args $sth->execute expects are values needed to fill in replaceable parameters (?) in the query.
my $sth = $dbh->prepare("INSERT INTO MyTable VALUES (?, ?)");
$sth->execute(1, "a");
$sth->execute(2, "b");
$sth->execute(3, "c");
In your case, since your query doesn't use any replaceable parameters, you should not pass any args to execute.
$sth->execute();
You're calling the execute command with incorrect parameters. You've already setup the SQL statement in the previous line, you don't need to do it again. Try this instead:
$sth->execute() or die "Couldn't execute statement: " . $dbh->errstr;
got a problem with perl dbi sqlite.
I have set up a database (and checked it with sqlite command line).
Now i want to search in this database, which did not work.
So i tried to just do a 'SELECT *'
this prints only the first element in the database, but not as it should everything in this table.
I think the error that causes the select * to fail is the same that prevents me from using "like %..%" stuff.
This is the relevant code, if the code is correct and the database table seems good what else could have caused the problems ?
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","","") || die "Cannot connect: $DBI::errstr";
my $sth = $dbh->prepare('SELECT * FROM words');
$sth->execute;
my #result = $sth->fetchrow_array();
foreach( #result) {
print $_;
}
fetchrow_array() only fetches one row.
Try
while ( my #row = $sth->fetchrow_array ) {
print "#row\n";
}
According to the documentation, fetchrow_array
Fetches the next row of data and returns it as a list containing the field values.
If you want all of the data you can call fetchrow_array (or fetchrow_arrayref) repeatedly until you reach the end of the table, or you can use fetchall_arrayref:
The fetchall_arrayref method can be used to fetch all the data to be returned from a prepared and executed statement handle. It returns a reference to an array that contains one reference per row
The code would look like this
use strict;
use warnings;
use DBI;
my $dbfile = 'words.db';
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile", '', '') or die "Cannot connect: $DBI::errstr";
my $sth = $dbh->prepare('SELECT * FROM words');
$sth->execute;
my $result = $sth->fetchall_arrayref;
foreach my $row ( #$result ) {
print "#$row\n";
}
I have been trying to use sql NOW() function while I update a table. But nothing happens to that date field, I think DBI just ignores that value. Code is :
dbUpdate($id, (notes => 'This was an update', filesize => '100.505', dateEnd => 'NOW()'));
and the function is :
sub dbUpdate {
my $id = shift;
my %val_hash = #_;
my $table = 'backupjobs';
my #fields = keys %val_hash;
my #values = values %val_hash;
my $update_stmt = "UPDATE $table SET ";
my $count = 1;
foreach ( #fields ) {
$update_stmt .= "$_ = ? ";
$update_stmt .= ', ' if ($count != scalar #fields);
$count++;
}
$update_stmt .= " WHERE ID = ?";
print "update_stmt is : $update_stmt\n";
my $dbo = dbConnect();
my $sth = $dbo->prepare( $update_stmt );
$sth->execute( #values, $id ) or die "DB Update failed : $!\n";
$dbo->disconnect || die "Failed to disconnect\n";
return 1;
}#dbUpdate
As you can see this is a "dynamic" generation of the sql query and hence I dont know where an sql date function(like now()) come.
In the given example the sql query will be
UPDATE backupjobs SET filesize = ? , notes = ? , dateEnd = ? WHERE ID = ?
with param values
100.55, This was an update, NOW(), 7
But the date column still shows 0000-00-........
Any ideas how to fix this ?
I have been trying to use sql NOW() function while I update a table. But
nothing happens to that date field, I think DBI just ignores that
value.
No, it doesn't. But the DB thinks you are supplying a datetime or timestamp data type when you are in fact trying to add the string NOW(). That of course doesn't work. Unfortunately DBI cannot find that out for you. All it does is change ? into an escaped (via $dbh->quote()) version of the string it got.
There are several things you could do:
Supply a current timestamp string in the appropriate format instead of the string NOW().
If you have it available, you can use DateTime::Format::MySQL like this:
use DateTime::Format::MySQL;
dbUpdate(
$id,
(
notes => 'This was an update',
filesize => '100.505',
dateEnd => DateTime::Format::MySQL->format_datetime(DateTime->now),
)
);
If not, just use DateTime or Time::Piece.
use DateTime;
my $now = DateTime->now->datetime;
$now =~ y/T/ /;
dbUpdate(
$id,
(notes => 'This was an update', filesize => '100.505', dateEnd => $now));
Tell your dbUpdate function to look for things like NOW() and react accordingly.
You can do something like this. But there are better ways to code this. You should also consider that there is e.g. CURRENT_TIMESTAMP() as well.
sub dbUpdate {
my $id = shift;
my %val_hash = #_;
my $table = 'backupjobs';
my $update_stmt = "UPDATE $table SET ";
# Check for the NOW() value
# This could be done with others too
foreach ( keys %val_hash ) {
if ($val_hash{$_} =~ m/^NOW\(\)$/i) {
$update_stmt .= "$_ = NOW()";
$update_stmt .= ', ' if scalar keys %val_hash > 1;
delete $val_hash{$_};
}
}
# Put everything together, join keeps track of the trailing comma
$update_stmt .= join(', ', map { "$_=?" } keys %val_hash );
$update_stmt .= " WHERE ID = ?";
say "update_stmt is : $update_stmt";
say "values are: ", join(', ', values %val_hash);
my $dbo = dbConnect();
my $sth = $dbo->prepare( $update_stmt );
$sth->execute( values %val_hash, $id ) or die "DB Update failed : $!\n";
$dbo->disconnect || die "Failed to disconnect\n";
return 1;
}
Write your queries yourself.
You're probably not going to do it and I'll not add an example since you know how to do it anyway.
Here's something else: Is this the only thing you do with your database while your program runs? It is not wise to connect and disconnect the database every time you make a query. It would be better for performance to connect the database once you need it (or at the beginning of the program, if you always use it) and just use this dbh/dbo everywhere. It saves a lot of time (and code).
Sorry but you can't use NOW() as an interpolated value like that.
when a ? is used in an SQL statement, the corresponding value is (via some mechanism or other) passed to the database escaped, so whatever value is interpreted as a string, not as SQL. So you are in effect attempting to use the string 'NOW()' as a date value, not the function NOW().
To use NOW() as a function, you will have to insert it into the SQL itself rather than pass it as a bound value. This means you will either have to use a hack of your dbupdate function or write a new one, or obtain the time as a string in perl and pass the resulting string the dbupdate.
For the past couple of hours I've been trying to format a MySQL timestamp using DATE_FORMAT and it doesn't do anything!
Perl Code:
use CGI;
use DBI;
my $q = new CGI;
# Database connection goes here
my $sth_select = $dbh->prepare(
"SELECT DATE_FORMAT(timestamp, '%m/%d/%y') FROM foo"
);
$sth_select->execute() || die "Unable to execute query: $dbh->errstr";
if (my $ref = $sth_select->fetchrow_hashref()) {
print $q->header;
print " TIME: $ref->{timestamp}";
exit;
}
Results
TIME:
It doesn't print the formatted time at all, it is blank!
When I attempt to print the timestamp it doesn't print anything, but if I were to remove DATA_FORMAT and just simply do a SELECT timestamp FROM foo, then it prints the timestamp just fine, albeit not formatted though. Can somebody provide their insight on this matter, please?
The hash returned has as keys column headers as provided by the database. When using a function like that, the column header is actually "DATE_FORMAT(timestamp, '%m/%d/%y')".
Try modifying your SQL to be:
my $sth_select = $dbh->prepare("SELECT DATE_FORMAT(timestamp, '%m/%d/%y') AS timestamp FROM foo");