Fetch 2 values using selectrow_array in Perl - mysql

I recently figured that there is a selectrow_array function to fetch values from databases. I'm getting following error when I'm using it. I wonder what is the issue here and couldn't find an alternative way to do this.
Code is:
my $db_connection = DBI->connect($dsn, $dbuser, $dbpassword ) or die $DBI::errstr;
my $sql_statement = "SELECT customer_id,quota FROM customer_call_quota WHERE quota>=1";
while (my $row = $db_connection->selectrow_array($sql_statement)) {
my ($cust_id, $quota) = #$row; #<---- error line
}
my $rc = $db_connection->disconnect ;
return "ok";
Error:
Can't use string ("value") as an ARRAY ref while "strict refs" in use at code.pl line ...

Two problems.
selectrow_array doesn't return a reference to an array. That's selectrow_arrayref.
selectrow_* only returns the first row.
Solutions:
# Wasteful
my $sth = $dbh->prepare($sql_statement);
$sth->execute();
while (my #row = $sth->fetchrow_array()) {
my ($cust_id, $quota) = #row;
...
}
or
my $sth = $dbh->prepare($sql_statement);
$sth->execute();
while (my ($cust_id, $quota) = $sth->fetchrow_array()) {
...
}
or
my $sth = $dbh->prepare($sql_statement);
$sth->execute();
while (my $row = $sth->fetch()) {
my ($cust_id, $quota) = #$row;
...
}

Related

Replacing a string with pdo on MySQL

I want to replace a string but I use PDO. Whatever I have tried is not working. Have you ever replaced a mysql string by using PDO connection?
Here is an example which is not working.
try
{
$image = $_POST['data1'];
$id= $_POST['data2'];
$insert = "UPDATE myTable SET images=REPLACE(images,':image','') where id = :id";
$insertStmt = $conn->prepare($insert);
$insertStmt->bindValue(":image", $image);
$insertStmt->bindValue(":id", $id);
$insertStmt->execute();
echo "success";
}
catch(PDOException $ex)
{
echo $ex->getMessage();
}
write :image instead of ':image'
$insert = "UPDATE myTable SET images=REPLACE(images,:image,'') where id = :id";

Complicated JOIN using multiple tables

For example
I have several profile tables, such as
music_profile
sports_profile
art_profile
All of these tables have matching names, and they all have a title column.
A second table contains alternative titles per any given profile table's row.
Their columns are essentially:
id, parent_id, parent_table, alt_title_001, alt_title_002, alt_title_003, alt_title_004, status, created, updated.
I want to
SELECT multiple column values
FROM music_profile, sports_profile, art_profile
WHERE title, alt_title_001, alt_title_002, alt_title_003, alt_title_004 are like a value
I can currently select columns using WHERE title LIKE and UNION, but I have no idea how to combine the alternate_titles table in the SELECT statement.
I've provided my current code below. The table for alternate_titles has not been implemented here.
I don't necessarily want a coded solution to this issue; I would just like a hint to get me on my way.
sub AdvancedSearchFormResults {
my $self = shift;
my $opts = ref $_[0] eq 'HASH' ? shift : {#_};
my $mode = shift;
my $order = shift;
my $limit = shift;
my #array;
my $where;
my $mode = $$opts{mode};
my $left_join_clause;
my (#where_stmt, #where_vals, #join);
if (defined $$opts{platform}) {
$where = $$opts{platform};
}
if ($$opts{'title_like'}) {
push(#where_stmt, "title like ?");
push(#where_vals, '%'.$$opts{'title_like'}.'%');
}
if ($$opts{'publisher'}) {
push(#where_stmt, "publisher = ?");
push(#where_vals, $$opts{'publisher'});
}
if ($$opts{'status'}) {
push(#where_stmt, "status = ?");
push(#where_vals, $$opts{'status'});
}
my $left_join_clause = scalar #join ? join("\n", #join) : "";
my $where_clause = #where_stmt ? "WHERE ".join(" AND ", #where_stmt) : "";
my $order_clause = length($order) ? "ORDER BY $order" : "";
my $limit_clause = length($limit) ? "LIMIT $limit" : "";
my $select_stmt;
if ($mode eq 'BUILD') {
$select_stmt = "SELECT
'$where' AS event,
ident,
title,
publisher
FROM $where
$left_join_clause
$where_clause
$order_clause
$limit_clause";
my $sth = $schema->prepare($select_stmt) or die $schema->errstr;
$sth->execute(#where_vals) or die $sth->errstr;
while (my $row = $sth->fetchrow_hashref()) {
push(#array, $row);
}
}
elsif ($mode eq 'UNION') {
my #select_stmts;
my #platforms = $self->ProfileTables();
my $total_platforms = -1;
foreach my $table (#platforms) {
$total_platforms++;
my $stmt = "(SELECT '$table' AS event,ident,title,publisher,status FROM $table $where_clause)";
push(#select_stmts, $stmt);
}
my $select_stmt .= "$select_stmts[0] UNION ALL";
$select_stmt .= join(' UNION ALL ', #select_stmts[ 1 .. 28 ]);
my #new_vals = (#where_vals, (#where_vals) x $total_platforms);
my $sth = $schema->prepare($select_stmt) or die $schema->errstr;
$sth->execute(#new_vals) or die $sth->errstr;
while (my $row = $sth->fetchrow_hashref()) {
push(#array, $row);
}
}
elsif ($mode eq 'REFRESH') {
print '
<div class="alert alert-danger" role="alert">
<strong>Please fill out at least one field.</strong>
</div>';
}
return #array;
}
A practical application of the code is below.
These variables are used as an example. This data would normally be supplied via a form.
my $title = 'Mario';
my $publisher = '';
my %params = (
title_like => $title,
publisher => $publisher,
status => 'a',
);
my #results = $results->AdvancedSearchFormResults(\%params);
print Data::Dumper::Dumper(\#results);
Dumper Results
$VAR1 = [
{
'ident' => '2109',
'title' => 'Mario Bros.',
'publisher' => 'Atari'
},
{
'ident' => '30',
'title' => 'Mario Bros.',
'publisher' => 'Atari'
},
{
'publisher' => 'Atari',
'ident' => '43',
'title' => 'Mario Bros.'
},
];
After a bit of headache and some intense googling I was able to come up with a solution.
The most basic solution to my problem is:
my #profiles = ('art', 'music', 'sports');
my #results;
my $blah;
my $sql;
foreach my $profile (#profiles) {
$sql = "SELECT
$profile.ident,
$profile.title,
$profile.status
FROM $profile
LEFT JOIN alternate_titles ON $profile.ident = alternate_titles.parent_ident
WHERE title like '%$blah%'
OR
CONCAT_WS(' ',alternate_titles.alt_title_001,alternate_titles.alt_title_002,alternate_titles.alt_title_003,alternate_titles.alt_title_004
AND alternate_titles.parent_table = '$profile'";
}
my $sth = $schema->prepare($sql) or die $schema->errstr;
$sth->execute() or die $sth->errstr;
while (my $data = $sth->fetchrow_hashref()) {
push(#results, $data);
}
This isn't immediately implementable in my code example, but this works as a great starting point.
I don't know that this is efficient, if anyone has a better solution, I'd love to see it.

Find how many times every word is repeated in db

Am using drupal to manage my content. I want to search all my contents title and body and find how many times each word is repeated in the whole contents.
It may be by an sql query, but I have no experience with sql.
Any ideas?
This code searches the body field and ALL fields of ANY Content Types for a specific string. You can run it via command line. Say you save it as "fieldsearch.php", you can then run it as:
php fieldsearch.php "myStringForWhichToSearch"
You need to fill in your connection data and database name. It outputs the array of matching nodes but you can format that output into anything you'd like (I recommend csv).
<?php
//Set Parameters here
$env = "dev"; // Options [dev|prod] - Defaults to dev
$prodConnection = array(
"host" => "",
"user" => "",
"pass" => ""
);
$devConnection = array(
"host" => "",
"user" => "",
"pass" => ""
);
//Use the selected env settings
if($env == "prod"){
$connection = $prodConnection;
} else {
$connection = $devConnection;
}
function getTables($con, $database){
//Get the set of field tables
$sql = "SHOW TABLES FROM $database";
$result = mysqli_query($con, $sql);
if (!$result) {
echo "DB Error, could not list tables\n";
echo 'MySQL Error: ' . mysql_error();
exit;
}
$tables = array();
while ($row = mysqli_fetch_row($result)) {
$tables[] = $row[0];
}
mysqli_free_result($result);
return $tables;
}
function getFieldTables($con,$database){
$allTables = getTables($con, $database);
$fieldTables = array();
foreach($allTables as $key => $table){
if( isFieldTable($table) ){
$fieldTables[] = $table;
}
}
//add the common tables
$fieldTables[] = "field_data_body";
$fieldTables[] = "field_data_comment_body";
return $fieldTables;
}
function isFieldTable($table){
//echo $table . "\n";
if( stripos($table, "field_data_field") !== FALSE){
return TRUE;
}
}
//Set the search term here:
if (array_key_exists(1, $argv)) {
$searchString = $argv[1];
}
else {
die('usage: php fieldsearch.php "search string"' . "\n");
}
$databaseName = "myDatabaseName";
$outArray = array();
//Connect
$con=mysqli_connect($connection['host'],$connection['user'],$connection['pass'],$databasePrefix.$databaseNum);
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
//getFieldTables
$fieldTables = getFieldTables($con, $databaseName);
//Query each field tables data for the string in question
foreach($fieldTables as $key => $table){
//get Field value column name
$valueCol = str_replace("field_data_field_", '', $table);
$result = mysqli_query($con,"SELECT
entity_id
FROM
$table
WHERE
field_" . $valueCol . "_value
LIKE
'%$searchString%';");
if($result){
while($row = mysqli_fetch_assoc($result)){
$dataArray[$table][$row['entity_id']]['nid'] = $row['entity_id'];
}
}
}
//Add the body table
$result = mysqli_query($con,"SELECT
entity_id
FROM
field_data_body
WHERE
body_value
LIKE
'%$searchString%';");
if($result){
while($row = mysqli_fetch_assoc($result)){
$dataArray['field_data_body'][$row['entity_id']]['nid'] = $row['entity_id'];
}
}
var_dump($dataArray);

Laravael4 db raw query using ON DUPLICATE KEY UPDATE drops error

I'm really fighting with a laravel ON DUPLICATE KEY UPDATE query I can't get it to work, so the query basically looks like
foreach ($queries as $query) {
$update_time = array('update_time' => date('Y-m-d H:i:s'));
$query = array_merge($update_time, $query);
$keysString = implode(", ", array_keys($query));
$indexes = "";
$values = "";
$updates = "";
foreach ($query as $i=>$v){
$values .= ':'.$v.',';
$updates .= $i.'="'.$v.'",';
}
//$holder = rtrim(str_repeat('?,', count($query)),',');
$updates = rtrim($updates,',');
DB::statement("INSERT INTO products ({$keysString}) VALUES ({rtrim($values,',')}) ON DUPLICATE KEY UPDATE {rtrim($updates,',')}")
}
but I get
SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters
How do I make a prepared statement in laravel4 for raw queries?
By default Laravel binds its data using ? and you are binding your data with :foo, meaning there is a mixture of the two approaches and PDO is getting sad about it.
PDO: Invalid parameter number: mixed named and positional parameters
Something like this should get you going in the right direction:
foreach ($queries as $query) {
// Add the update time without merging stuff
$query['update_time'] = date('Y-m-d H:i:s');
// How many bits of data do we have
$bindingCount = count($query);
// Same as before, just get the keys
$keyString = implode(", ", array_keys($query));
// Start off a bindings array with just the values
$bindings = array_values($query);
$updates = [];
foreach ($query as $field => $value){
$updates[] = "{$field} = ?";
$bindings[] = $value;
}
$valueString = implode(',', array_fill(0, $bindingCount, '?'));
$updateString = implode(',', $updates);
DB::statement("INSERT INTO products ({$keyString}) VALUES ({$valueString}) ON DUPLICATE KEY UPDATE {$updateString}", $bindings);
}

Perl and DBI - Load array Problem

I am new to Perl and need some help.
In Mysql I have a table with a todo-List filled up.
At the beginning of my script, I want to add these values to "my %todo"
But I can't figure out how to do this...
Any idea?
OK, let's play martian rover though I'd rather see the code.
Do you use warnings; use strict? If not, do it. If yes, are there any warnings or errors?
If you put a print "while\n"; into your while loop, how many while's will you get on screen? How many records are there in the table?
If you use DBI, turn on exceptions: $dbh->RaiseError(1); ($dbh is you database handle here) before any operations with DB.
I don't understand why you ask for "load array" and specify a hash %todo, but if you want to read a table into memory once, you should look at the $dbh->selectall_arrayref() method.
Added: See if this get you started:
my $dsn = '...';
my $user = '...';
my $password = '...';
my $dbh = DBI->connect( $dsn, $user, $password, { RaiseError => 1, AutoCommit => 0 } );
my $sql = 'SELECT ... FROM Todo';
my %todo = ();
if (0) {
my $sth = $dbh->prepare( $sql );
$sth->execute();
while (my $aref = $sth->fetchrow_arrayref()) {
$todo{ $aref->[ 0 ] } = $aref->[ 1 ];
}
$sth->finish();
} else {
my $aref = $dbh->selectall_arrayref($sql);
for (#$aref) {
$todo{ $_->[ 0 ] } = $_->[ 1 ];
}
}
for (keys( %todo )) {
print $_, "\n", $todo{ $_ }, "\n\n";
}
my $rc = $dbh->disconnect();
use strict;
use warnings;
my $dbh = $dbh->connect;
$dbh->{RaiseError} = 1;
my $sth = $dbh->prepare(q/select id, to_do from to_do_table/);
$sth->execute;
my %todo;
while(my ($id, $to_do) = $sth->fetchrow) {
$todo{$index_column} = $to_do;
}
$dbh->disconnect;