Execute SQL file in Perl
Not exactly sure what you want...
Once you create a DBI object, you can use it over and over again. Here I'm reading SQL statement after SQL statement from a file and processing each and every one in order:
use DBI;
my $sqlFile = "/home/user1/tools/mytest.sql"
my $dbh = DBI::Connect->new($connect, $user, $password)
or die("Can't access db");
# Open the file that contains the various SQL statements
# Assuming one SQL statement per line
open (SQL, "$sqlFile")
or die("Can't open file $sqlFile for reading");
# Loop though the SQL file and execute each and every one.
while (my $sqlStatement = <SQL>) {
$sth = dbi->prepare($sqlStatement)
or die("Can't prepare $sqlStatement");
$sth->execute()
or die("Can't execute $sqlStatement");
}
Notice that I'm putting the SQL statement in the prepare
and not the file name that contains the SQL statement. Could that be your problem?
How to load the .sql file from perl script and execute the sql commands in the perl script
If I read your problem correctly, your biggest challenge is breaking apart the file into separate sql statements, SQL::SplitStatement is usefull but beware it's not bullet proof.
Here's an example of how you could accomplish this;
#!/usr/bin/env perl
use strict;
use warnings;
use diagnostics;
use DBI;
use File::Slurp;
use SQL::SplitStatement;
my $sql_blob = read_file( 'test1.sql' ) ;
my @sql_list = SQL::SplitStatement->new()->split($sql_blob);
my $dbh = DBI->connect( "dbi:mysql:my_database:localhost:3306", "username", "password" );
foreach my $sql (@sql_list) {
print 'Executing ', $sql;
$dbh->do($sql) or print "Can't do ", $dbh->errstr;
}
How to execute a Pl sql 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();
How to run and link a .sql file from Perl
In Perl you use the DBI database interface. In your case, you will also be using something like the DBD::MySQL
driver.
There is lots of help available on this topic (including lots of questions on this site).
As for the specific question of your .sql file, there are a few approaches you could take, depending on how fancy you want to get:
- You could just copy and paste the commands into your program as you write it.
- You could execute an external program that will run the .sql file (for example, by using
system()
). - You could programmatically read in the .sql file and send the commands from within your program. A module could help you with this (I found
SQL::Script
on CPAN, which looks useful, though I don't have any experience with it).
I suggest you pick an approach, try it, and ask if you have any specific problems.
Perl DBI - run SQL Script with multiple statements
The database controls how many statements can be executed at a time. I can't remember if Oracle allows multiple statements per prepare
or not (MySQL does). Try this:
my $dbh = DBI->connect(
"dbi:Oracle:dbname",
"username",
"password",
{
ChopBlanks => 1,
AutoCommit => 1,
RaiseError => 1,
PrintError => 1,
FetchHashKeyName => 'NAME_lc',
}
);
$dbh->do("
CREATE TABLE test_dbi1 (
test_dbi_intr_no NUMBER(15),
test_dbi_name VARCHAR2(100)
);
UPDATE mytable
SET col1=1;
CREATE TABLE test_dbi2 (
test_dbi_intr_no NUMBER(15),
test_dbi_name VARCHAR2(100)
);
");
$dbh->disconnect;
Of course, you get better error handling if you break the statements up. You can use a simple parser to break the string up into individual statements:
#!/usr/bin/perl
use strict;
use warnings;
my $sql = "
CREATE TABLE test_dbi1 (
test_dbi_intr_no NUMBER(15),
test_dbi_name VARCHAR2(100)
);
UPDATE mytable
SET col1=';yes;'
WHERE col2=1;
UPDATE mytable
SET col1='Don\\'t use ;s and \\'s together, it is a pain'
WHERE col2=1;
CREATE TABLE test_dbi2 (
test_dbi_intr_no NUMBER(15),
test_dbi_name VARCHAR2(100)
);
";
my @statements = ("");
#split the string into interesting pieces (i.e. tokens):
# ' delimits strings
# \ pass on the next character if inside a string
# ; delimits statements unless it is in a string
# and anything else
# NOTE: the grep { ord } is to get rid of the nul
# characters the split seems to be adding
my @tokens = grep { ord } split /([\\';])/, $sql;
# NOTE: this ' fixes the stupid SO syntax highlighter
#this is true if we are in a string and should ignore ;
my $in_string = 0;
my $escape = 0;
#while there are still tokens to process
while (@tokens) {
#grab the next token
my $token = shift @tokens;
#if we are in a string
if ($in_string) {
#add the token to the last statement
$statements[-1] .= $token;
#setup the escape if the token is \
if ($token eq "\\") {
$escape = 1;
next;
}
#turn off $in_string if the token is ' and it isn't escaped
$in_string = 0 if not $escape and $token eq "'";
$escape = 0; #turn off escape if it was on
#loop again to get the next token
next;
}
#if the token is ; and we aren't in a string
if ($token eq ';') {
#create a new statement
push @statements, "";
#loop again to get the next token
next;
}
#add the token to the last statement
$statements[-1] .= $token;
#if the token is ' then turn on $in_string
$in_string = 1 if $token eq "'";
}
#only keep statements that are not blank
@statements = grep { /\S/ } @statements;
for my $i (0 .. $#statements) {
print "statement $i:\n$statements[$i]\n\n";
}
How to pass parameters from Perl script to SQL script and execute it from Perl script?
I used $sth->fetch
instead of $sth->fetchrow_array
after execution of .sql as below.
$sth = $dbh->prepare( "select * from alleMagic;" );
$sth->execute;
# Column binding is the most efficient way to fetch data
my $rv = $sth->bind_columns(\$lname, \$fname, \$ext );
while ($sth->fetch) {
print "$lname, $fname, $ext \n";
}
Related Topics
How to Use Like Condition in SQL with Numeric Field
SQL to Find Duplicate Entries (Within a Group)
How to Call a User Defined Function to Use with Select, Group By, Order By
Postgresql - Order by an Array
SQL Server: How to Group Multiple Row Values into Separate Columns
Sqlite Equivalent of Postgresql's Greatest Function
How to Use a Reserved Word in SQL as a Table Name
How to Fill Missing Dates and Values in Partitioned Data
Insert Inserted Id to Another Table
How to Write the Equivalent SQL Case Statement for Query Given Below
Query Last N Related Rows Per Row
SQL Varchar(Max) VS Varchar(Fix)
Sqlserver Case Expressions - Short Circuit Evaluation
#1452 - Cannot Add or Update a Child Row: a Foreign Key Constraint Fails
This SQL 'Order By' Is Not Working Properly