php mysql while loop query optimization - php

I have php/mysql script running which is like this:
$sql = "select a.column1 from table1 a";
$query = mysql_query($sql);
while ($fec = mysql_fetch_assoc($query)) {
$sub1 = "select column1,column2 from subtable1 where id=" . $fec['a.column1'];
$subquery1 = mysql_query($sub1);
while ($subfec1 = mysql_fetch_assoc($subquery1)) {
//all data .....
}
$sub1 = "select column1,column2 from subtable2 where id=" . $fec['a.column1'];
$subquery2 = mysql_query($sub2);
while ($subfec2 = mysql_fetch_assoc($subquery2)) {
//all data .....
}
$sub2 = "select column1,column2 from subtable3 where id=" . $fec['a.column1'];
$subquery3 = mysql_query($sub3);
while ($subfec3 = mysql_fetch_assoc($subquery3)) {
//all data .....
}
}
Now I've many many many records in table1, subtable1, subtable2 and subtable3. And problem is that it takes around 7 hours to display the results. Moreover the CPU Usage is 100%
Please suggest the optimization tips to overcome this issue.

Use a single query to get all records
SELECT
a.column1,
s.column1,
s.column2,
s2.column1,
s2.column2,
s3.column1,
s3.column2
FROM table1 a
LEFT JOIN subtable1 s ON s.id = a.column1
LEFT JOIN subtable2 s2 ON s.id = a.column1
LEFT JOIN subtable3 s3 ON s.id = a.column1
Here
$sql="
SELECT
a.column1 acolumn1,
s.column1 scolumn1,
s.column2 scolumn2,
s2.column1 s2column1,
s2.column2 s2column2,
s3.column1 s3column1,
s3.column2 s3column2
FROM table1 a
LEFT JOIN subtable1 s ON s.id = a.column1
LEFT JOIN subtable2 s2 ON s.id = a.column1
LEFT JOIN subtable3 s3 ON s.id = a.column1";
$query=mysql_query($sql);
while ($fec=mysql_fetch_assoc($query)) {
// display any info here
}
Use aliases for accessing different table columns

Related

PHP SQL i another SQL query

Description:
table1 - columns: f1,f2,f3,f4,f5
in these columns I have rom_number for temperature sensors
table2 - columns: act_temperature, rom_number
I need act_temperature from table2 for each rom_number stored in table1 (cols f1,f2,...)
I have code:
// main loop
$rows = $db->query("SELECT * FROM tabela1 WHERE active='on' ");
$row = $rows->fetchAll();
foreach ($row as $a) {
$f1 = $a['f1'];
$f2 = $a['f2'];
$f3 = $a['f3'];
$f4 = $a['f4'];
$f5 = $a['f5'];
}
How to change the code ?
You have to LEFT JOIN on table 2 for each columns f1,f2,...
$sql = "SELECT t1.*,
t2_1.act_temperature as tmp1,
t2_2.act_temperature as tmp2,
t2_3.act_temperature as tmp3,
t2_4.act_temperature as tmp4,
t2_5.act_temperature as tmp4
FROM tabela1 t1
LEFT JOIN tabela2 t2_1 ON t2_1.rom_number = t1.f1
LEFT JOIN tabela2 t2_2 ON t2_2.rom_number = t1.f2
LEFT JOIN tabela2 t2_3 ON t2_3.rom_number = t1.f3
LEFT JOIN tabela2 t2_4 ON t2_4.rom_number = t1.f4
LEFT JOIN tabela2 t2_5 ON t2_5.rom_number = t1.f5
WHERE active='on' ";
Then, $a should have following keys : f1,f2,...,f5,tmp1,tmp2,...,tmp5.

How can I join 3 tables in SQL

Here is the query I created :
$query = "SELECT address_details.company, address_details.po_box,
address_details.town, letter_details.address_id,
letter_details.attn, letter_details.create_date,
letter_details.ref_no, letter_details.refference,
letter_details.letter_body, letter_details.print_date
FROM letter_details
join address_details ON address_details.id = letter_details.address_id
join signatories ON (letter_details.id = signatories.id)
WHERE letter_details.id='" .$_GET['id'] . "'";
Try using this query.
$query = "SELECT ad.company, ad.po_box,
ad.town, ld.address_id,
ld.attn, ld.create_date,
ld.ref_no, ld.refference,
ld.letter_body, ld.print_date
FROM letter_details ld
left join address_details ad ON (ad.id = ld.address_id)
left join signatories s ON (ld.id = s.id)
WHERE ld.id='" .$_GET['id'] . "'";
First, you should alias for better readibility,
check if you get something in $_GET[id]
echo $_GET[id];
then assign it, (or you may set it as well, if you're using a class)
$fltr = $_GET[id];
And, try to use LEFT JOIN ;
SELECT b.company, b.po_box,
b.town, a.address_id,
a.attn, a.create_date,
a.ref_no, a.refference,
a.letter_body, a.print_date
FROM letter_details AS a LEFT JOIN address_details AS b ON b.id = a.address_id
LEFT JOIN signatories AS c ON (a.id =c.id)
WHERE a.id='$fltr'

How do I nest joins inside a from statement in Codeigniter

Okay, I've been tasked with rewriting a small, old PHP app in Codeigniter, and I ran into a bit a road bump. I'm not sure how to go about handling the joins in the query.
FROM(
(
(
(
(mobiledoc.labdata labdata JOIN mobiledoc.items items
ON (labdata.ItemId = items.itemID)
) JOIN mobiledoc.enc enc
ON (labdata.EncounterId = enc.encounterID)
) JOIN mobiledoc.users users_patient
ON (users_patient.uid = enc.patientID)
) JOIN mobiledoc.users users_Provider
ON (users_Provider.uid = enc.doctorID)
) JOIN mobiledoc.facilitygroupmembers facilitygroupmembers
ON (enc.facilityId = facilitygroupmembers.FacilityId)
)
And then after that FROM there are a few more joins, which I think would be fairly easy.
JOIN mobiledoc.facilitygroups facilitygroups ON (facilitygroups.Id = acilitygroupmembers.GroupId)
JOIN mobiledoc.patients patients ON (enc.patientID = patients.pid)
Any help would be greatly appreciated.
UPDATE:
I decided to just put the nested joins inside the for statement, and move on. Here's the original query.
$result = mysql_query("SELECT patients.ControlNO AS PatientID, users_patient.ulname AS patulname,
users_patient.ufname AS patufname, users_patient.uminitial AS patuminitial, users_patient.dob AS
patdob, users_Provider.ulname AS ULname, users_Provider.ufname AS UFname, items.itemName,
labdata.Notes,enc.date, enc.startTime FROM(((((mobiledoc.labdata labdata JOIN mobiledoc.items
items ON (labdata.ItemId = items.itemID)) JOIN mobiledoc.enc enc ON (labdata.EncounterId =
enc.encounterID)) JOIN mobiledoc.users users_patient ON (users_patient.uid = enc.patientID)) JOIN
mobiledoc.users users_Provider ON (users_Provider.uid = enc.doctorID)) JOIN
mobiledoc.facilitygroupmembers facilitygroupmembers ON (enc.facilityId =
facilitygroupmembers.FacilityId)) JOIN mobiledoc.facilitygroups facilitygroups ON
(facilitygroups.Id = facilitygroupmembers.GroupId) JOIN mobiledoc.patients patients ON
(enc.patientID = patients.pid) WHERE (facilitygroups.Name = '". $_POST['facility_id'] . "') AND
(items.itemName LIKE '%X RAY%' OR items.itemName LIKE '%Cast%' OR items.itemName LIKE '%Splint%'
OR items.itemName LIKE '%DEXA%') AND (enc.VisitType NOT IN ('', 'MT', 'TEL')) AND (enc.`date` =
'" . $_POST['txtYear'] . "-" . $_POST['txtMonth'] . "-" . $_POST['txtDay'] ."') ORDER BY
enc.startTime ASC") or die ("could not execute query!");
Here's the new query:
$this->db->select('patients.ControlNO as id');
$this->db->select('users_patient.ulname as lastName');
$this->db->select('users_patient.ufname as firstName');
$this->db->select('users_patient.uminitial as mInitial');
$this->db->select('users_patient.dob as dob');
$this->db->select('users_Provider.ulname as phys_lastName');
$this->db->select('items.itemName');
$this->db->select('labdata.notes');
$this->db->select('enc.date');
$this->db->select('enc.startTime');
$this->db->from('((((mobiledoc.labdata labdata JOIN mobiledoc.items items ON (labdata.ItemId
= items.itemID)) JOIN mobiledoc.enc enc ON (labdata.EncounterId = enc.encounterID)) JOIN
mobiledoc.users users_patient ON (users_patient.uid = enc.patientID)) JOIN mobiledoc.users
users_Provider ON (users_Provider.uid = enc.doctorID)) JOIN mobiledoc.facilitygroupmembers
facilitygroupmembers ON (enc.facilityId = facilitygroupmembers.FacilityId)) JOIN
mobiledoc.facilitygroups facilitygroups ON (facilitygroups.Id = facilitygroupmembers.GroupId)
JOIN mobiledoc.patients patients ON (enc.patientID = patients.pid)');
$this->db->where($where_array);
$this->db->like($like_array);
$this->db->or_like($or_like_array);
$this->db->where_not_in('enc.VisitType', $not_in);
$this->db->order_by('enc.startTime', 'asc');
$this->db->get();
And the output from that query:
SELECT `patients`.`ControlNO` as id, `users_patient`.`ulname` as lastName,
`users_patient`.`ufname` as firstName, `users_patient`.`uminitial` as mInitial,
`users_patient`.`dob` as dob, `users_Provider`.`ulname` as phys_lastName, `items`.`itemName`,
`labdata`.`notes`, `enc`.`date`, `enc`.`startTime` FROM ((((((mobiledoc.labdata labdata JOIN
mobiledoc.items items ON (labdata.ItemId = items.itemID)) JOIN mobiledoc.enc enc ON
(labdata.EncounterId = enc.encounterID)) JOIN mobiledoc.users users_patient ON (users_patient.uid
= enc.patientID)) JOIN mobiledoc.users users_Provider ON (users_Provider.uid = enc.doctorID))
JOIN mobiledoc.facilitygroupmembers facilitygroupmembers ON (enc.facilityId =
facilitygroupmembers.FacilityId)) JOIN mobiledoc.facilitygroups facilitygroups ON
(facilitygroups.Id = facilitygroupmembers.GroupId) JOIN mobiledoc.patients patients ON
(enc.patientID = patients.pid)) WHERE `facilitygroups`.`Name` = 0 AND `enc`.`date` = '12/05/2014'
AND `enc`.`VisitType` NOT IN ('', 'MT', 'TEL') AND `items`.`itemName` LIKE '%X RAY%' OR
`items`.`itemName` LIKE '%DEXA%' OR `0` LIKE '%items.itemName%' ORDER BY `enc`.`startTime` asc
With CI's active record you can easily join tables by using the following format
$qry = $this->db->select('*')
->from('table1')
->where('table1.id', 1)
->join('table2','table2.t_id = table1.id')
->get();
For more information take a look at CI's active record documentation
Also you can specify the join type by adding a third parameter to the join() function
$this->db->join('table3', 'table3.id = table2.t_id', 'left');

php mysql query dynamic Group by value

Hi I have a mysql query that I want to get results by different order by values.
here is the code.
$strQuery =
"SELECT
category.short_description AS category,
asset.asset_code AS code,
asset_model_number.short_description AS model,
asset_custom_field_helper.cfv_1 AS mnfserial,
asset_custom_field_helper.cfv_6 AS proctype,
asset_custom_field_helper.cfv_7 AS hdd,
asset_custom_field_helper.cfv_8 AS type,
asset_custom_field_helper.cfv_9 AS cond,
asset_custom_field_helper.cfv_10 AS drive,
asset_custom_field_helper.cfv_12 AS os,
asset_custom_field_helper.cfv_13 AS cpu,
asset_custom_field_helper.cfv_14 AS ram,
COUNT(*) AS total
FROM
asset_transaction
LEFT JOIN asset
ON asset_transaction.asset_id = asset.asset_id
LEFT JOIN asset_model
ON asset.asset_model_id = asset_model.asset_model_id
LEFT JOIN asset_model_number
ON asset.asset_model_number_id = asset_model_number.asset_model_number_id
LEFT JOIN asset_custom_field_helper
ON asset.asset_id = asset_custom_field_helper.asset_id
LEFT JOIN user_account
ON asset.created_by = user_account.user_account_id
LEFT JOIN category
ON asset_model.category_id = category.category_id
WHERE asset_transaction.transaction_id = ($txnid)
GROUP BY model";
$objDatabase = QApplication::$Database[1];
// Perform the Query
$objDbResult = $objDatabase->Query($strQuery);
This section I want to get results group by model
echo "<h3>Total Model No<br></h3><strong>";
while ($mixRow = $objDbResult->FetchArray()) {
echo $mixRow['model']. " = " .$mixRow['total'];
echo "<br><strong>";
}
Below section I want the results group by type
echo "<h3>Total Products<br></h3><strong>";
echo "<br>";
while ($row = $objDbResult->FetchArray()) {
echo $row['type']. " = " .$row['total'];
echo "<br><strong>";
I want to avoid writing the sql query each time, instead want to use this query and define my order by value somewhere. How can I do this?
I hope this helps you :)
function getQuery( $order_by_string )
{
return $query = 'Your query .... ORDER BY '.$order_by_string
}
$query = getQuery("something");
You should consider making a query builder class, so you can create queries more freely.
Anyhow, to just set the group by, you can create the function getQueryGroupBy($query,$type) as following:
function getQueryGroupBy($query, $type) {
return $query . 'GROUP BY ' . $type;
}
Your query would be:
$strQuery = "SELECT
category.short_description AS category,
asset.asset_code AS code,
asset_model_number.short_description AS model,
asset_custom_field_helper.cfv_1 AS mnfserial,
asset_custom_field_helper.cfv_6 AS proctype,
asset_custom_field_helper.cfv_7 AS hdd,
asset_custom_field_helper.cfv_8 AS type,
asset_custom_field_helper.cfv_9 AS cond,
asset_custom_field_helper.cfv_10 AS drive,
asset_custom_field_helper.cfv_12 AS os,
asset_custom_field_helper.cfv_13 AS cpu,
asset_custom_field_helper.cfv_14 AS ram,
COUNT(*) AS total
FROM
asset_transaction
LEFT JOIN asset
ON asset_transaction.asset_id = asset.asset_id
LEFT JOIN asset_model
ON asset.asset_model_id = asset_model.asset_model_id
LEFT JOIN asset_model_number
ON asset.asset_model_number_id = asset_model_number.asset_model_number_id
LEFT JOIN asset_custom_field_helper
ON asset.asset_id = asset_custom_field_helper.asset_id
LEFT JOIN user_account
ON asset.created_by = user_account.user_account_id
LEFT JOIN category
ON asset_model.category_id = category.category_id
WHERE
asset_transaction.transaction_id = ($txnid)";
You would then call the function like this:
$query = $this->setGroupBy($strQuery, 'model');
or
$query = $this->setGroupBy($strQuery, 'type');
EDIT
So you would probably end up with this:
$baseQuery =
"SELECT
category.short_description AS category,
asset.asset_code AS code,
asset_model_number.short_description AS model,
asset_custom_field_helper.cfv_1 AS mnfserial,
asset_custom_field_helper.cfv_6 AS proctype,
asset_custom_field_helper.cfv_7 AS hdd,
asset_custom_field_helper.cfv_8 AS type,
asset_custom_field_helper.cfv_9 AS cond,
asset_custom_field_helper.cfv_10 AS drive,
asset_custom_field_helper.cfv_12 AS os,
asset_custom_field_helper.cfv_13 AS cpu,
asset_custom_field_helper.cfv_14 AS ram,
COUNT(*) AS total
FROM
asset_transaction
LEFT JOIN asset
ON asset_transaction.asset_id = asset.asset_id
LEFT JOIN asset_model
ON asset.asset_model_id = asset_model.asset_model_id
LEFT JOIN asset_model_number
ON asset.asset_model_number_id = asset_model_number.asset_model_number_id
LEFT JOIN asset_custom_field_helper
ON asset.asset_id = asset_custom_field_helper.asset_id
LEFT JOIN user_account
ON asset.created_by = user_account.user_account_id
LEFT JOIN category
ON asset_model.category_id = category.category_id
WHERE asset_transaction.transaction_id = ($txnid)";
$objDatabase = QApplication::$Database[1];
// Create the query
$modelQuery = getQueryGroupBy($baseQuery, 'model');
// Perform the Query
$objDbResultByModel = $objDatabase->Query($modelQuery);
echo "<h3>Total Model No<br></h3><strong>";
while ($mixRow = $objDbResultByModel->FetchArray()) {
echo $mixRow['model']. " = " .$mixRow['total'];
echo "<br><strong>";
}
// Create the query
$typeQuery = getQueryGroupBy($baseQuery, 'type');
// Perform the Query
$objDbResultByType = $objDatabase->Query($typeQuery);
echo "<h3>Total Products<br></h3><strong>";
echo "<br>";
while ($row = $objDbResultByType->FetchArray()) {
echo $row['type']. " = " .$row['total'];
echo "<br><strong>";
}
function getQueryGroupBy($query, $type) {
return $query . ' GROUP BY ' . $type;
}

PHP while loop returning only one row when SUM added to multiple JOIN query

I have a query like this:
$query = "SELECT a.sender_id,
a.recipient_id,
a.form_id, due_date,
a.completed,
f.name,
p.priority,
u.first_name,
u.last_name,
SUM(a.completed) as completed_sum
FROM form_assignments a
JOIN forms f ON (form_id = f.id)
JOIN users u ON (sender_id = u.id)
JOIN priorities p ON (priority_id = p.id)
WHERE recipient_id = '{$_SESSION['user_id']}'
ORDER BY due_date ASC";
And a while loop like this:
$assignment_count = (mysqli_num_rows($result));
$assignments_row = array();
while ($row = mysqli_fetch_array($result)) {
$sender = $row['first_name'] . ' ' . $row['last_name'];
$form_id = $row['form_id'];
$form_name = $row['name'];
$priority = $row['priority'];
$due_date = date('m/d/Y', strtotime($row['due_date']));
$completed = $row['completed'];
$not_done = $assignment_count - $row['completed_sum'];
}
And it's only returning one row. It seems my SUM(a.completed) as completed_sum is causing the issues because the query worked fine before I added it, but I want to add up all the values in completed to use in my $not_done variable.
Can anyone help clarify what I'm doing wrong?
When you use an aggregate function like SUM, all the results will be aggregated into one row unless you use a GROUP BY clause to segregate them. But it looks to me like you don't need a SUM in the first place. Your loop is subtracting this value from a total, so you just need the value from each row -- when you subtract them all you'll have subtracted the total. So just select a.completed rather than SUM(a.completed).
For $not_done, you need to initialize it before the loop:
$not_done = $assignment_count;
Then during the loop you should do a running subtraction:
$not_done -= $row['completed'];
Try this query :
SELECT
a.sender_id,
a.recipient_id,
a.form_id,
a.due_date,
a.completed,
f.name,
p.priority,
u.first_name,
u.last_name,
b.completed as completed_sum
FROM
form_assignments AS a
LEFT JOIN (
SELECT form_id,SUM(completed) FROM form_assignments GROUP BY form_id
) AS b ON (a.form_id = b.form_id)
LEFT JOIN forms AS f ON (form_id = f.id)
LEFT JOIN users AS u ON (sender_id = u.id)
LEFT JOIN priorities AS p ON (priority_id = p.id)
WHERE
recipient_id = '{$_SESSION['user_id']}'
ORDER BY due_date ASC

Categories