perl update oracle database with values from another database - mysql

I am writing a perl script to update a table in an oracle database with data from a mysql database.
I am new to perl so any help would be appreciated.
I currently have the following which does not update the oracle database but also does not throw any errors.
The databases have both been initialised.
I would like the oracle tblrecommendations table to have the performance updated with whats in the mysql tblrecommendations table.
Thanks in advance.
#transfer data
sub do_crc_company_performance {
my ($sth_mysql, $sth_oracle);
my $sql_details = <<END_SQL;
select
tblRecommendations.code,
tblRecommendations.performance
from
crc.tblRecommendations
where
length(tblRecommendations.code) = '3'
END_SQL
# variables to bind values to
my ($code, $performance);
eval {
# prepare our select statement for mysql
$sth_mysql = $dbh_mysql->prepare($sql_details);
$sth_mysql->execute;
$sth_mysql->bind_columns(\($code, $performance));
# create oracle insertion query
$sth_oracle = $dbh_oracle->prepare(q{UPDATE TBLRECOMMENDATIONS
SET PERFORMANCE = '$performance'
WHERE CODE = '$code'});
while ( $sth_mysql->fetch ) {
$performance = Encode::decode_utf8($performance); # set the flag
# feed the data into the tblRecommendations table
$sth_oracle->execute();
}
};
if ($#) {
# what went wrong
push (#errors, "Unable to update company details: $#");
# rollback our transaction
$dbh_oracle->rollback()
}
$sth_oracle->finish if ($sth_oracle);
$sth_mysql->finish if ($sth_mysql);
}

Your problem is your q{} quoting, which is literal string quoting with no interpolation. Thus, you are searching for records where the code field is set to the five character literal string value $code.
One solution would be to quote with interpolation — either "" or qq{}. However, this is prone to unpleasant SQL injection and thus strongly discouraged.
A better solution, as you discovered, is to use bind values and let the RDBMS driver take care of quoting and escaping for you. However, you do not need an intermediary $sth in this case:
$dbh_ora->do(q{UPDATE tbl SET foo = ? WHERE bar = ?}, undef, $new_foo, $bar);
Now, I infer that you have RaiseError set (good!), and you don't care about the number of rows UPDATEd, so you don't even need to capture the return value of that call to do().

For anyone interested in the final solution that worked for me, here it is.
sub do_crc_company_performance {
my ($sth_mysql, $sth_oracle);
my $sql_details = <<END_SQL;
select
tblRecommendations.code,
tblRecommendations.performance
from
crc.tblRecommendations
where
length(tblRecommendations.code) = '3'
END_SQL
# variables to bind values to
my ($code, $performance);
eval {
# prepare our select statement for mysql
$sth_mysql = $dbh_mysql->prepare($sql_details);
$sth_mysql->execute;
$sth_mysql->bind_columns(\$code, \$performance);
# create oracle insertion query
while ( $sth_mysql->fetch ) {
$performance = Encode::decode_utf8($performance); # set the flag
# feed the data into the tblRecommendations table
$sth_oracle = $dbh_oracle->do('UPDATE tblrecommendations SET performance = ? WHERE code = ?', undef, $performance, $code);
}
};
if ($#) {
# what went wrong
push (#errors, "Unable to update company details: $#");
# rollback our transaction
}
}

I don't see a COMMIT in your code, which is necessary to make your changes permanent. Somewhere in there (either after each insert or after the fetch loop) you want:
$sth_oracle->commit;

Related

Is it possible to insert sql query in php array value?

for($count = 0; $count < count($_POST["item_sub_category"]); $count++)
{
$data = array(
':item_sub_category_id'
=> SELECT r_name FROM Repair where r_id = $_POST["item_sub_category"][$count]
);
$query = "INSERT INTO Repairlog (description,visitID) VALUES (:item_sub_category_id,'1')";
$statement = $connect->prepare($query);
$statement->execute($data);
}
As far as concerns, your code won't work. The SQL query that you are passing as a parameter will simply be interpreted as a string.
You could avoid the need for a loop by taking advantage of the INSERT INTO ... SELECT ... syntax. The idea is to generate an IN clause that contains all values that are in the array, and then run a single query to insert all records at once.
Consider:
$in = str_repeat('?,', count($_POST["item_sub_category"]) - 1) . '?';
$query = "INSERT INTO Repairlog (description,visitID) SELECT r_name, 1 FROM Repair WHERE r_id IN ($in)";
$statement = $connect->prepare($query);
$statement->execute($_POST["item_sub_category"]);
Note: it is likely that visitID is an integer and not a string; if so, then it is better not to surround the value with single quotes (I removed them in the above code).
TLDR; No.
Your question can be re-framed as: Can I write SQL code in php. The answer is NO. You can write the SQL code within a String type variable (or parameter) in php.
This is a general rule for any programming language, you cannot have multiple languages within the same file, as the language parser will not be able understand which syntax is that.
In order to embed a different language in another language, you need some kind of separator that will define when the new language or special type will start and when it will end.

Select or Return "field" names from a query (not table) in MySQL

I have a Dynamic Pivot in MySQL (see this question: MySQL "Multi-Dimensional?" Dynamic Pivot)
I want to know the Column/As/Field names as if it were a table and I queried INFORMATION_SCHEMA (which if this was a REAL table, would be easy enough: MySQL query to get column names?).
But, I can find no question or reference to a function or SELECT option to get the Column/As/Field names from a query. Is this possible? If so, how?
Using Perl to access MySQL (http://dbi.perl.org/).
So, flipping this around... we know the fixed columns. So, if we use the same basic query that creates the Pivot to begin with, we can get a GROUP_CONCAT of the names.
SET #sql = NULL;
SELECT GROUP_CONCAT(qrv.req_name) INTO #sql
FROM (SELECT qrt.req_name FROM qual_requirment_values qrv JOIN qual_requirment_types qrt ON qrt.id = qrv.req_type_id) qrv;
SET #sql = CONCAT('r.rank,r.member_type,im.name,qrv.grouping,', #sql);
SELECT #sql;
This can then be split into an array and used.
Seems like the long way around, but in the absence of something else it will work for my application. Seems horribly inefficient! :)
The better answer, thanks to #OllieJones. The Data Base Interface used to access MySQL should provide a way.
In my case (Perl), the answer is here: http://www.perlmonks.org/?node_id=264623
my $sql = ... [some query];
my $sth = $dbh->prepare($sql);
$sth->execute();
my $field_name_arrayref = $sth->{NAME};
Further to the answer, this is the full method within my MySQL package. do() is our generic DBI method that returns queries in an AoA. Adapting that method to create do_fieldNames();
## Tested Method
sub do_fieldNames {
my ($self, $sql, $has_results) = #_;
my ($sth, $rv, #row, #query_results);
## Execute the SQL statement
$sth = $$self->prepare($sql);
$rv = $sth->execute or &error(3306, __LINE__, __FILE__, $sql, $$self->errstr);
return undef unless $rv > 0;
## SOLUTION >> Field Name arrayref, part of the standard included DBI Perl Module
my $field_name_arrayref = $sth->{NAME};
## Parse the results
if ($has_results || $sql =~ /^select/i) {
while (#row = $sth->fetchrow_array) {
push #query_results, [ #row ];
}
}
## Return results
return (\#query_results, $field_name_arrayref) ;
}

oracle sql developer not storing unicode

I am inserting a text field from a mysql database into an oracle clob column.
When I do this it appears that the oracle table does not support unicode as the ' and " characters are showing up as ???.
I have to use clob as the text field is much larger then varchar2 can hold.
Thanks in advance for any help provided on this matter.
Perl script to move data from mysql database into the oracle database:
sub do_crc_company_overview {
my ($sth_mysql, $sth_oracle);
my $sql_details = <<END_SQL;
select
tblRecommendations.code,
tblRecommendations.description,
tblRecommendations.overview,
tblRecommendations.performance,
tblRecommendations.updated
from
crc.tblRecommendations
where
tblRecommendations.code not in (
select
tblRecommendations.code
from
crc.tblRecommendations
where
tblRecommendations.code regexp "[0-9]"
)
END_SQL
# variables to bind values to
my ($code, $description, $overview, $performance, $updated);
eval {
# first clean out the oracle table
$sth_oracle = $dbh_oracle->prepare(q{delete from tblRecommendations});
$sth_oracle->execute;
# create oracle insertion query
$sth_oracle = $dbh_oracle->prepare(q{
insert into
tblRecommendations (
code,
description,
overview,
performance,
updated
)
values
(?, ?, ?, ?, ?)
});
# prepare our select statement for mysql
$sth_mysql = $dbh_mysql->prepare($sql_details);
$sth_mysql->execute;
$sth_mysql->bind_columns(\($code, $description, $overview, $performance, $updated));
while ( $sth_mysql->fetch ) {
# feed the data into the tblRecommendations table
# in the database, which has been cleaned out
$sth_oracle->execute($code, $description, $overview, $performance, $updated);
}
};
Pulling the data from the oracle database:
class CrcCompanyInfo < Sequel::Model(IM.database[:tblRecommendations])
#Only selects companies that have one or more active instruments
set_dataset select(
:tblRecommendations__code => :code,
:tblRecommendations__description => :crc_description,
:tblRecommendations__overview => :crc_overview,
:tblRecommendations__performance => :crc_performance,
)
This works as I am able to pull data from other tables in the database.
I have narrowed it down to the following characters not coming through properly.
“ = left quote = “
†= right quote = ”
‘ = left single quote = ‘
’ = right single quote = ’
— = en dash = –
– = em dash = —
• = hyphen = -
… = ellipsis = …
I have tried doing an update on the oracle table to change these but the oracle table doesn't hold the funny keys it just changes them all to '???' therefore the update didin't work. Can someone give me any insite on how I might update the data before or while it gets input into the oracle database?
Thanks
I figured this out myself.
I just had to force the utf8 flag on all the data being pushed into the oracle database.
code as follows:
$description = Encode::decode_utf8($description);
Cheers for everyones help.

MySQL Dynamic Query Statement in Python with Dictionary

Very similar to this question MySQL Dynamic Query Statement in Python
However what I am looking to do instead of two lists is to use a dictionary
Let's say i have this dictionary
instance_insert = {
# sql column variable value
'instance_id' : 'instnace.id',
'customer_id' : 'customer.id',
'os' : 'instance.platform',
}
And I want to populate a mysql database with an insert statement using sql column as the sql column name and the variable name as the variable that will hold the value that is to be inserted into the mysql table.
Kind of lost because I don't understand exactly what this statement does, but was pulled from the question that I posted where he was using two lists to do what he wanted.
sql = "INSERT INTO instance_info_test VALUES (%s);" % ', '.join('?' for _ in instance_insert)
cur.execute (sql, instance_insert)
Also I would like it to be dynamic in the sense that I can add/remove columns to the dictionary
Before you post, you might want to try searching for something more specific to your question. For instance, when I Googled "python mysqldb insert dictionary", I found a good answer on the first page, at http://mail.python.org/pipermail/tutor/2010-December/080701.html. Relevant part:
Here's what I came up with when I tried to make a generalized version
of the above:
def add_row(cursor, tablename, rowdict):
# XXX tablename not sanitized
# XXX test for allowed keys is case-sensitive
# filter out keys that are not column names
cursor.execute("describe %s" % tablename)
allowed_keys = set(row[0] for row in cursor.fetchall())
keys = allowed_keys.intersection(rowdict)
if len(rowdict) > len(keys):
unknown_keys = set(rowdict) - allowed_keys
print >> sys.stderr, "skipping keys:", ", ".join(unknown_keys)
columns = ", ".join(keys)
values_template = ", ".join(["%s"] * len(keys))
sql = "insert into %s (%s) values (%s)" % (
tablename, columns, values_template)
values = tuple(rowdict[key] for key in keys)
cursor.execute(sql, values)
filename = ...
tablename = ...
db = MySQLdb.connect(...)
cursor = db.cursor()
with open(filename) as instream:
row = json.load(instream)
add_row(cursor, tablename, row)
Peter
If you know your inputs will always be valid (table name is valid, columns are present in the table), and you're not importing from a JSON file as the example is, you can simplify this function. But it'll accomplish what you want to accomplish. While it may initially seem like DictCursor would be helpful, it looks like DictCursor is useful for returning a dictionary of values, but it can't execute from a dict.

Prepared statement fetches all the results in db, but not one I ask for

Trying to make my blog secure and learning prepared statements.
Although I set the variable, I still get all the entries from database. $escapedGet is real variable when I print it out. It's obviously a rookie mistake, but I cant seem to find an answer.
I need to get the data where postlink is $escapedGet not all the data.
$escapedGet = mysql_real_escape_string($_GET['article']);
// Create statement object
$stmt = $con->stmt_init();
// Create a prepared statement
if($stmt->prepare("SELECT `title`, `description`, `keywords` FROM `post` WHERE `postlink` = ?")) {
// Bind your variable to replace the ?
$stmt->bind_param('i', $postlink);
// Set your variable
$postlink = $escapedGet;
// Execute query
$stmt->execute();
$stmt->bind_result($articleTitle, $articleDescription, $articleKeywords);
while($stmt->fetch()) {
echo $articleTitle, $articleDescription, $articleKeywords;
}
// Close statement object
$stmt->close();
}
just tryed this: echo $escapedGet;
echo $_Get['artcile']
and got - some_other
thats the same entry that I have saved in database as postlink
tried to shande postlink to id, and then it worked. but why not with postlink tab?
When you are binding your data using 'i' modifier, it gets bound as integer.
Means string will be cast to 0 in the final statement.
But as mysql does type casting, your strings become zeroes in this query:
SELECT title FROM post WHERE postlink = 0;
try it and see - for the textual postlinks you will have all your records returned (as well as a bunch of warnings).
So, bind strings using s modifier, not i