Associate 2 table values in perl - mysql

I have 2 tables in mysql database: CUSTOMER and GROUP
The CUSTOMER table:
NAME |PHONE
A |222
B |333
C |777
D |888
E |111
F |555
and so on.
The GROUP table has only 3 value:
GN | NUM
NEW |807
OLD |455
INT |504
I would like to get the following result:
A, NEW, 807
B, OLD, 455
C, INT, 504
D, NEW, 807
E, OLD, 455
F, INT, 504
and so on..
The GROUP table must repeat until the end of CUSTOMER table.
Here is my code:
#!/usr/bin/perl
# PERL MODULES
use DBI;
use strict;
use warnings;
# MYSQL CONFIG VARIABLES
my $dsn = 'DBI:mysql:test:127.0.0.1';
my $tablename = "CUSTOMER";
my $user = "root";
my $pw = "xxxx";
# DEFINE A MySQL QUERY
my $myquery1 = "SELECT NAME FROM $tablename";
# PERL CONNECT()
my $dbh = DBI->connect($dsn, $user, $pw);
# EXECUTE THE QUERY
my $getname = $dbh->prepare($myquery1);
$getnum->execute();
my $getlogin = $dbh->prepare("select * from GROUP");
$getlogin->execute();
my($login, $password);
# FETCHROW ARRAY
while (my $name = $getname->fetchrow_array()) {
while (my #row = $getlogin->fetchrow_array()) {
my ($gn,$num) = #row;
$login=$gn;
$password=$num;
print "$name\t\t $login \t\t $password \n";
}
}
When i execute my code i get:
A NEW 807
B OLD 455
C INT 504
DBD::mysql::st fetchrow_array failed: fetch() without execute() at ./main.pl line 29.
How can i do this?
Any help would be appreciated.

First of all, you have a typo -- you are doing $getnum->execute() not $getname->execute(). Did you really run the exact code you pasted?
You are encountering an error after the third iteration because you only have three rows of data in the GROUP table. You need to either start the loop again with a fresh query (perform the execute() inside the first while loop, just before you start the second), or cache all its data into an array that you can loop over repeatedly:
my $getname = $dbh->prepare($myquery1);
my $getlogin = $dbh->prepare("select * from GROUP");
# FETCHROW ARRAY
$getname->execute();
while (my $name = $getname->fetchrow_array())
{
$getlogin->execute();
while (my #row = $getlogin->fetchrow_array())
{
my ($gn,$num) = #row;
my $login=$gn;
my $password=$num;
print "$name\t\t $login \t\t $password \n";
}
}

It sounds like you just want the rows in the CUSTOMER table to be assigned alternating values, rotating through the GROUP table -- and you don't much care who gets what value (or you would have put ORDERs into your SELECTs).
What I'd do is: add a column to the GROUP table with the values 0, 1 and 2; give the CUSTOMER table an incrementing id; and join them on (CUSTOMER.id % 3 = GROUP.id). That rotates the GROUP values down the CUSTOMER table in what I think is exactly the way you want.
ALTER TABLE `GROUP` ADD COLUMN id INT UNSIGNED NOT NULL, ADD INDEX idx_id (id);
UPDATE GROUP SET id=0 WHERE GN='NEW';
UPDATE GROUP SET id=1 WHERE GN='OLD';
UPDATE GROUP SET id=2 WHERE GN='INT';
ALTER TABLE `CUSTOMER` ADD COLUMN
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT;
Then it's just one SELECT to get the pairings you want:
SELECT NAME, GN, NUM FROM `GROUP`, CUSTOMER WHERE GROUP.id = CUSTOMER.id % 3;
(P.S. I suggest not naming a table an SQL keyword like "GROUP", you'll have to quote it every time you use it.)

The problem is that you're calling $getlogin->fetchrow_array after all elements are processed. This happens when CUSTOMER loop doing second iteration. You should call $getlogin->execute just in the start of CUSTOMER loop. Like this:
while (my $name = $getname->fetchrow_array()) {
## start new query each time we want to loop GROUP table
my $getlogin = $dbh->prepare("select * from GROUP");
$getlogin->execute();
while (my #row = $getlogin->fetchrow_array()) {
But this can kill performance of the script. I suggest you to select all GROUPs before CUSTOMERs loop into array and use it instead of loading data from DB each iteration.

Related

SQL run command if row exists

I'm new to MySQL and I'm trying to make the following pseudocode work:
SELECT IF(
EXISTS(SELECT * FROM users WHERE `email`="admin" AND `token`="blablabla"),
(UPDATE * FROM sometable WHERE `var`="notimportant"),
"NOT_AUTHORIZED");
What I'm trying to achieve is running code based on the presence of a row, and if it doesn't exists return a message, or something usable. If it does exists, run another SQL command instead, and return those results.
Is this possible?
Your intent is a bit hard to follow from the invalid syntax. But the gist of your question is that you can use a where clause:
UPDATE sometable
SET . . .
WHERE var = 'notimportant' AND
EXISTS (SELECT 1 FROM users WHERE email = 'admin' AND token = 'blablabla');
You can also represent this as a JOIN. Assuming the subquery returns at most one row:
UPDATE sometable t CROSS JOIN
(SELECT 1
FROM users
WHERE email = 'admin' AND token = 'blablabla'
LIMIT 1
) x
SET . . .
WHERE var = 'notimportant' ;

Perl query and get column name

I need to make a query where I will be looking for a specific string through several columns and I need to know which column (name) contains the value that I need.
In the example below I need a query where I can ask which column contains the value 1000000000002101214 and that it returns f1. DB is MySQL and I need the programming to be done in Perl.
+---------------------+---------------------+---------------------+
| f1 | f2 | f3 |
+---------------------+---------------------+---------------------+
| 1000000000002101214 | 1000000000001989129 | 1000000000001881637 |
| 1000000000002080453 | 1000000000001968481 | 1000000000001862284 |
| 1000000000002085919 | 1000000000001973677 | 1000000000001866854 |
| 1000000000002075076 | 1000000000001963189 | 1000000000001857288 |
+---------------------+---------------------+---------------------+
I was able to find an almost-answer to my question from another site where I could get the column names of the fields in the table with the following:
my #cols = #{$sth->{NAME}}; # or NAME_lc if needed
while (#row = $sth->fetchrow_array) {
print "#row\n";
}
$sth->finish;
foreach ( #cols ) {
printf( "Note: col : %s\n", $_ );
}
The problem is partially resolved. In the example table I provided in the original question I needed to know on which column my answer resides, the query contains several OR statemens:
SELECT * FROM table WHERE (f1='1000000000002101214' OR f2='1000000000002101214' OR f3='1000000000002101214')
And I need the result to show that the column name where the number is located is f1. So....
Any thoughts?
I don't even know where to start
Check out Perl's DBI module. Read the documentation. You'll have to do something like below:
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
#Connect to your database, provide id, password
my $dbh = DBI->connect('dbi:mysql:perltest','root','password') or die "Connection Error: $DBI::errstr\n";
#Write your query
my $sql = "select * from database_schema";
my $sth = $dbh->prepare($sql);
#Execute it
$sth->execute or die "SQL Error: $DBI::errstr\n";
#Fetch the value
while (my #row = $sth->fetchrow_array) {
#Do something with your result
print "#row\n";
}
If you are new to Perl then see: http://learn.perl.org/
Edit: Query to find out column name based on the value found in column.
Select 'f1'
from database_schema
where database_schema.f1 = 1000000000002101214
union
Select 'f2'
from database_schema
where database_schema.f2 = 1000000000002101214
union
Select 'f3'
from database_schema
where database_schema.f3 = 1000000000002101214

Updating Multiple Rows and Columns of database in Joomla

I have a database similar to this:
table name = jos_school ... id = Primary key, name = Unique key
id name no_of_students no_of_staffs fees
1 schoolA 0 0 0
2 schoolB 0 0 0
...
...
In phpMyAdmin I did something like this, and it worked (successfully updated multiple rows and columns),
UPDATE jos_school
SET no_of_students = CASE name
WHEN 'schoolA' THEN '1523'
WHEN 'schoolB' THEN '546'
....
END,
no_of_staffs = CASE name
WHEN 'schoolA' THEN '1234'
WHEN 'schoolB' THEN '346'
....
END
WHERE name IN ('schoolA', 'schoolB')
However, I was not able to update the table USING JOOMLA's Update methods. I don't want to use foreach and update the table over 1000 times. I want to execute a single query.
I've also read: http://docs.joomla.org/Inserting,_Updating_and_Removing_data_using_JDatabase#Updating_a_Record
and dint found it helpful in this case.
So, can someone point me to the right direction.
You can query as below,
// Create a new query object.
$db = &JFactory::getDBO();
$query = $db->getQuery(true);
// Select the required fields from the table.
$query="UPDATE jos_school SET no_of_students = CASE name";
foreach($data as $d)
{
$query.=".....";
}
$query.=".....";
$db->setQuery((string)$query);
Hope that helps ...

Sub queries in Yii

I have the following mysql query which works well in phpmyadmin when i execute it :
"SELECT * FROM accounts_users WHERE id = ( SELECT teacher_id FROM general_teacher_student_associations WHERE student_id = 509 )";
But when i execute via Yii, it breaks :
$query = "SELECT * FROM accounts_users WHERE id = ( SELECT teacher_id FROM general_teacher_student_associations WHERE student_id =509 )";
$command = Yii::app()->db->createCommand($query);
$teachers_list = $command->query();
return $teachers_list;
509 is a dynamically fetched value.
1. What am i doing wrong?
2. Can this be done in a better way?
/******Edited***********/
Found the error : The sub query returns more than one row. Can i use single query to fetch all the values other than using a foreach loop and then inside that executing another query?
Solution : (Accepting Daniels answer since his comment actually solved the issue)
$query = "SELECT * FROM accounts_users WHERE id IN ( SELECT teacher_id FROM general_teacher_student_associations WHERE student_id =509 )";
$command = Yii::app()->db->createCommand($query);
$teachers_list = $command->queryAll();
return $teachers_list;
p.s: This is an edition work and i am not allowed to touch model and hence using model relations is out of window and thats why i ended up with this
Try:
$teachers_list = Yii::app()->db->createCommand()->select('ausers.*')
->from('accounts_users ausers')
->join('( SELECT teacher_id FROM general_teacher_student_associations WHERE student_id = 509 ) as teachers ON teachers.teacher_id = ausers.id')
->queryRow();

How do I change the case on every field in a mysql table in one call?

I have a table with 27 varchar fields. I want to make all fields lowercase, but i want to do it in one short mysql call.
This does a single field:
UPDATE table
SET field = LOWER(field)
How do I do the equivalent of this (which doesn't work):
UPDATE table
SET * = LOWER(*)
You can't do it with your creative attempt SET * = LOWER(*) etc.
You can however do it like this:
UPDATE table SET
column1 = LOWER(column1),
column2 = LOWER(column2),
-- etc, listing all text type columns
columnN = LOWER(columnN);
The reason there's no "shortcut" is probably because this pattern is so infrequently needed.
The consensus is that this cannot be done in a single mysql query.
Here is a super quick PHP script that does this for N fields (thanks for the idea #alex):
$sql = "SHOW COLUMNS
FROM table";
$results = mysqli_query($dbcon,$sql);
while($column = mysqli_fetch_assoc($results))
{
$column = $column["Field"];
$sql = "UPDATE table
SET $column = LOWER($column)";
$success = mysqli_query($dbcon,$sql);
}