How to execute a Pl sql file from a perl script - sql

Hi folks can you please help me in understanding how to call a pl sql file from perl script
I have a pl sql file like this
DECLARE
x NUMBER := 100;
BEGIN
FOR i IN 1..10 LOOP
IF MOD(i,2) = 0 THEN -- i is even
INSERT INTO temp VALUES (i, x, 'i is even');
ELSE
INSERT INTO temp VALUES (i, x, 'i is odd');
END IF;
x := x + 100;
END LOOP;
COMMIT;
END;
The file is named test.sql I want to call this file from a perl script. I know first we have to connect to db and then perform the process but I Don now know how to execute this file from a perl script

Basically you need to
use the DBI module with the appropriate driver (Oracle or whatever)
slurp in the script into a variable by using plain perl
open a DB connection
prepare the slurped in script
execute the statement handle
disconnect from the DB
Here is an example (I am not showing how to slurp in the script):
use DBI;
use DBD::Oracle;
my $service="xxx";
my $user = "yyy";
my $pass = "zzz";
my $DBH = DBI->connect
(
"dbi:Oracle:$service",
"$user", "$pass",
{
RaiseError => 0,
PrintError => 0,
AutoCommit => 0,
ShowErrorStatement => 0
}
) or die;
my $script = qq(
declare
x number := 1;
begin
insert into xxx values (x);
commit;
end;
);
my $sth = $DBH->prepare($script) or die;
$sth->execute() or die;
$DBH->disconnect();

Related

How to check a variable is it the Database and print it out?

I got a list of variables to loop through the database. How can I detect the variable is not in the database? What query should I use? How to print out error message once detected the variable is not in database.
My Code:
$variable = $sql->{'variable'};
foreach my $sql (#Records){
**Below statement will select existed variable, what should I change to make it select not existed variable**
$sqlMySQL = "Select LOT from table where LOT like '%$variable%'";
}
**If not exist**{
print("Not exist")
}
Expected result:
While the $variable loop through the database, if the $variable not exist in the database then print out the $variable or not exist.
Thanks for viewing, comments and answers.
I would go about it similar to the below.
A list of variables - Place those variables in an array (aka a list)
What query should I use - One that will only select exactly what you need and store it in the best dataset for traversal (selectall_hashref)
While the $variable loop through the database - Would require a DBI call for each $variable, so instead loop through your array to check for existence in the hash.
EXAMPLE
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
my $dbh =
DBI->connect( "dbi:SQLite:dbname=test.db", "USERNAME", "PASSWORD",
{ RaiseError => 1 },
) or die $DBI::errstr;
my #vars = ( 25, 30, 40 );
my $hash_ref =
$dbh->selectall_hashref( q / SELECT LOT FROM table /, q / LOT / );
$dbh->disconnect();
foreach (#vars) {
if ( exists $hash_ref->{$_} ) {
print $_ . "\n";
}
else {
print "Does not exist\n";
}
}
Something similar to that will pull all the LOT column values for your table into a hash key value pair that you can then compare against your array in a foreach loop.

PDO output parameter error

I am using this SP, am getting both the result when using mysql workbench.
CREATE PROCEDURE SP(IN _start INT,IN _end INT,INOUT _count INT)
BEGIN
SET _count = (SELECT COUNT(*) FROM tbl);
SET #qry = CONCAT('select * from tbl limit ', _start, ',', _end);
PREPARE stmt FROM #qry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
But when using with PDO am returning this error
$c=0;
$stmt = $this->_dbc->getConnection()->prepare("CALL SP(0,10,:count)");
$stmt->bindParam(":count",$c,PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT,0);
$stmt->execute();
return $c;
PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1414 OUT or INOUT argument 3 for routine db22.SP is not a variable or NEW pseudo-variable in BEFORE trigger
But on changing
$this->_dbc->getConnection()->prepare("CALL SP(0,10,**:count**)");
to
$this->_dbc->getConnection()->prepare("CALL SP(0,10,#count)");
am not returning any error, but always getting the count as 0.
Whats the difference between :count and #count ?
How to get exact count via pdo ?
You can do the following workaround:
$dbh = $this->_dbc->getConnection()
$stmt = $dbh->prepare("CALL SP(0,10,#count)");
$stmt->execute();
$sql = "SELECT #count AS count";
$stmt = $dbh->prepare($sql);
$stmt->execute();
You can find more here: http://www.php.net/manual/en/pdo.prepared-statements.php#101993

How to get return value from and SQL Stored Procedure Run Using Perl?

I am running a stored procedure in MS SQL using perl
The return value is an integer (0 = if ok, and some negative values if it exited early at certain points)
while the code runs the SP - it doesn't give me the return value at all.
my code:
use dbd::odbc;
#...
$dbh->do("use XXX"); #Name of the DB
my $sth = $dbh->prepare( "
DECLARE \#return_value int
EXEC \#return_value = [dbo].[test1]
\#BeginDate = '11/11/2011',
\#EndDate = '11/11/2011'
select \#return_value
");
$sth->execute( );
#### AFTER THIS I TRIED:
while ( #dbrow = $sth->fetchrow_array( ) ) {
$return_value = #dbrow[0]
}
#### i also tried:
my $return_value = $sth->fetchrow_array( )
#### both get nothing.
When I use regular SELECT queries, both of the above work.
What does it return? Try this:
while ( #dbrow = $sth->fetchrow_array( ) ) {
use Data::Dumper;
$Data::Dumper::Useqq = 1;
print Dumper( { "got row" => \#dbrow } );
}
Try executing the procedure in SQL server and make sure it returns
atleast one record
Check the return value of the execute statement, print error if it is not successful
$sth->execute() or die "Couldn't execute: " . $sth->errstr;
Check the number of rows from sth
if ($sth->rows == 0) {print "Zero records"}
I'm not sure if this helps but can you try this one.
while ( $row_ref = $sth->fetch_arrayref() ) {
my $return_value = $row_ref->[0];
print $return_value;
}

How can I UPDATE rows returned by a SELECT in a loop?

I have a loop on the rows returned by an SQL SELECT statement, and, after some processing on a row's data, I sometimes want to UPDATE the row's value. The processing in the loop's body is non-trivial, and I can't write it in SQL. When I try to execute the UPDATE for the selected row I get an error (under Perl's DBD::SQLite::st execute failed: database table is locked). Is there a readable, efficient, and portable way to achieve what I'm trying to do? Failing that, is there a DBD or SQLite-specific way to do it?
Obviously, I can push the updates in separate data structure and execute them after the loop, but I'd hate the code's look after that.
If you're interested, here is the corresponding Perl code.
my $q = $dbh->prepare(q{
SELECT id, confLoc FROM Confs WHERE confLocId ISNULL});
$q->execute or die;
my $u = $dbh->prepare(q{
UPDATE Confs SET confLocId = ? WHERE id = ?});
while (my $r = $q->fetchrow_hashref) {
next unless ($r->{confLoc} =~ m/something-hairy/);
next unless ($locId = unique_name_state($1, $2));
$u->execute($locId, $r->{id}) or die;
}
Temporarily enable AutoCommit:
sqlite> .header on
sqlite> select * from test;
field
one
two
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
my $dbh = DBI->connect('dbi:SQLite:test.db', undef, undef,
{ RaiseError => 1, AutoCommit => 0}
);
test_select_with_update($dbh);
sub test_select_with_update {
my ($dbh) = #_;
local $dbh->{AutoCommit} = 1;
my $q = $dbh->prepare(q{SELECT field FROM test});
my $u = $dbh->prepare(q{UPDATE test SET field = ? WHERE field = ?});
$q->execute or die;
while ( my $r = $q->fetchrow_hashref ) {
if ( (my $f = $r->{field}) eq 'one') {
$u->execute('1', $f) or die;
}
}
}
After the code has been run:
sqlite> .header on
sqlite> select * from test;
field
1
two
Your problem is that you're using the same database handler to perform an update while you're in a fetching loop.
So have another instance of your database handler to perform the updates:
my $dbh = DBI->connect(...);
my $dbhForUpdate = DBI->connect(...) ;
Then use dbhForUpdate in your loop:
while(my $row = $sth->fetch()){
...
$dbhForUpdate->do(...) ;
}
Anyway, I wouldn't recommend doing this since there's good chances you run into concurrency issues at the database level.
More in answer to Zoidberg's comment but if your were able to switch to an ORM like Perl's DBIx::Class then you find that you could write something like this:
my $rs = $schema->resultset('Confs')->search({ confLocId => undef });
while ( my $data = $rs->next ) {
next unless $data->confLoc =~ m/(something)-(hairy)/;
if ( my $locId = unique_name_state( $1, $2 ) ) {
$data->update({ confLocID => $locid });
}
}
And if DBIx::Class doesn't grab your fancy there are a few others on CPAN like Fey::ORM and Rose::DB for example.

How can I avoid the program quitting when Perl's DBI encounters an error preparing a statement?

I'm making a script that goes through a table that contains all the other table names on the database. As it parses each row, it checks to see if the table is empty by
select count(*) cnt from $table_name
Some tables don't exist in the schema anymore and if I do that
select count(*)
directly into the command prompt, it returns the error:
206: The specified table (adm_rpt_rec) is not in the database.
When I run it from inside Perl, it appends this to the beginning:
DBD::Informix::db prepare failed: SQL: -
How can I avoid the program quitting when it tries to prepare this SQL statement?
One option is not to use RaiseError => 1 when constructing $dbh. The other is to wrap the prepare in an eval block.
Just put the calls that may fail in an eval block like this:
for my $table (#tables) {
my $count;
eval {
($count) = $dbi->selectrow_array("select count(*) from $table");
1; #this is here so the block returns true if it succeeds
} or do {
warn $#;
next;
}
print "$table has $count rows\n";
}
Although, in this case, since you are using Informix, you have a much better option: the system catalog tables. Informix keeps metadata like this in a set of system catalog tables. In this case you want systables:
my $sth = $dbh->prepare("select nrows from systables where tabname = ?");
for my $table (#tables) {
$sth->execute($table);
my ($count) = $sth->fetchrow_array;
$sth->finish;
unless (defined $count) {
print "$table does not exist\n";
next;
}
print "$table has $count rows\n";
}
This is faster and safer than count(*) against the table. Full documentation of the system catalog tables can be found in IBM Informix Guide to SQL (warning this is a PDF).
Working code - assuming you have a 'stores' database.
#!/bin/perl -w
use strict;
use DBI;
my $dbh = DBI->connect('dbi:Informix:stores','','',
{RaiseError=>0,PrintError=>1}) or die;
$dbh->do("create temp table tlist(tname varchar(128) not null) with no log");
$dbh->do("insert into tlist values('systables')");
$dbh->do("insert into tlist values('syzygy')");
my $sth = $dbh->prepare("select tname from tlist");
$sth->execute;
while (my($tabname) = $sth->fetchrow_array)
{
my $sql = "select count(*) cnt from $tabname";
my $st2 = $dbh->prepare($sql);
if ($st2)
{
$st2->execute;
if (my($num) = $st2->fetchrow_array)
{
print "$tabname: $num\n";
}
else
{
print "$tabname: error - missing?\n";
}
}
}
$sth->finish;
$dbh->disconnect;
print "Done - finished under control.\n";
Output from running the code above.
systables: 72
DBD::Informix::db prepare failed: SQL: -206: The specified table (syzygy) is not in the database.
ISAM: -111: ISAM error: no record found. at xx.pl line 14.
Done - finished under control.
This printed the error (PrintError=>1), but continued. Change the 1 to 0 and no error appears. The parentheses in the declarations of $tabname and $num are crucial - array context vs scalar context.