How do I nest joins inside a from statement in Codeigniter - php

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');

Related

Left joining two tables, multiple columns

I need to left join two tables: Cardealers and Applications.
I want to see which cardealers have received which applications.
Each application is forwarded to three cardealers thus my table structure is having these 3 columns: receiver_1, receiver_2, receiver_3.
Where the ID in the receiver columns is the same as the cardealer_id.
I have this code functioning for ONE and one column only:
$res1 = $wpdb->get_results( " SELECT leads.*, cardealers.*
FROM leads
LEFT JOIN cardealers ON leads.receiver_1 = cardealers.cardealer_id
WHERE leads.receiver_1 = cardealers.cardealer_id
AND cardealers.cardealer_id = '". $cardealer_id ."'" );
$res2 = $wpdb->get_results( " SELECT leads.*, cardealers.*
FROM leads
LEFT JOIN cardealers ON leads.receiver_2 = cardealers.cardealer_id
WHERE leads.receiver_2 = cardealers.cardealer_id
AND cardealers.cardealer_id = '". $cardealer_id ."'" );
$res3 = $wpdb->get_results( " SELECT leads.*, cardealers.*
FROM leads
LEFT JOIN cardealers ON leads.receiver_3 = cardealers.cardealer_id
WHERE leads.receiver_3 = cardealers.cardealer_id
AND cardealers.cardealer_id = '". $cardealer_id ."'" );
As you can see I do 3 separate statements which all works. But I want to combine these into one statement.
How do I do this?
Just keep adding the tables and alias them.
SELECT
leads.*, cardealers1.*, cardealers2.*, cardealers3*
FROM leads
LEFT JOIN cardealers as cardealers1
ON leads.receiver_1 = cardealers1.cardealer_id
LEFT JOIN cardealers as cardealers2
ON leads.receiver_2 = cardealers2.cardealer_id
LEFT JOIN cardealers as cardealers3
ON leads.receiver_3 = cardealers3.cardealer_id
WHERE
leads.receiver_1 = cardealers1.cardealer_id
AND leads.receiver_2 = cardealers2.cardealer_id
AND leads.receiver_3 = cardealers3.cardealer_id
AND cardealers.cardealer_id = '". $cardealer_id ."'
EDIT: it's best if you give an alias for the columns from each of the cardealers

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'

php mysql while loop query optimization

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

How to write MySQL aliases properly?

For all those that care, I found that I needed to re read the basics on querying. Once sorted, I realised I had a fair few errors throughout my code.
I've got a query I'm trying to build and I'm throwing up error after error regarding to ambiguity. Would anyone kindly show me how to execute MySQL aliases properly?
This is my code so far. It worked fine until I put the join in there. I suspect it's because I'm referencing 'wine' more than once in the same query, but that may be one of many problems.
$query =
"SELECT
wine_id,
wine_name,
winery_name,
region_name,
year,
variety
FROM
wine AS w,
winery,
region,
grape_variety
JOIN
wine
ON
grape_variety.variety_id = wine.wine_id
JOIN
wine_variety
ON
wine.wine_id = wine_variety.variety_id
WHERE
winery.region_id = region.region_id
AND
wine.winery_id = winery.winery_id";
if (!empty($wineName)) {
$query .= " AND wine_name = '{$wineName}'";
}
if (!empty($wineryName)) {
$query .= " AND winery_name = '{$wineryName}'";
}
// If the user has specified a region, add the regionName
// as an AND clause
if (isset($regionName) && $regionName != "All") {
$query .= " AND region_name = '{$regionName}'";
}
// If the user has specified a variety, add the grapeVariety
// as an AND clause
if (isset($grapeVariety) && $grapeVariety != "Riesling") {
$query .= " AND variety = '{$grapeVariety}'";
}
Try to do it this way:
SELECT w.wine_id, w.wine_name, winery_name, region_name, year, variety
FROM
wine AS w
join winery on w.winery_id = winery.winery_id
join region on winery.region_id = region.region_id,
join grape_variety on grape_variety.variety_id = w.wine_id
Your query must be like:
SELECT
w.wine_id,
w.wine_name,
wy.winery_name,-- I assume this column from table `wy`
r.region_name, -- column from table `region`
w.year,
w.variety
FROM wine w
INNER JOIN winery wy ON (wy.winery_id = w.winery_id )
INNER JOIN region r ON ( r.region_id = wy.region_id )
INNER JOIN grape_variety gv ON (gv.variety_id = w.wine_id)
INNER JOIN wine_variety wv ON (wv.variety_id = w.wine_id)
...
append other WHERE conditions here
Note: if you give table structure then it would be more clear, at first I assume whatever column you retrieve is from main table and
if all tables in query have same column name then use table_alias_name.column_name.
try this
SELECT
w.wine_id,
w.wine_name,
wy.winery_name,
r.region_name,
r.year,
wv.variety
FROM wine w
INNER JOIN winery wy ON (wy.winery_id = w.winery_id )
INNER JOIN region r ON ( r.region_id = wy.region_id )
INNER JOIN grape_variety gv ON (gv.variety_id = w.wine_id)
INNER JOIN wine_variety wv ON (wv.variety_id = w.wine_id)
Use This one
$query =
"SELECT
w.wine_id,
w.wine_name,
winery.winery_name,
region.region_name,
year,
grape_variety.variety
FROM
wine AS w,
winery,
region,
grape_variety
JOIN
wine
ON
grape_variety.variety_id = wine.wine_id
JOIN
wine_variety
ON
wine.wine_id = wine_variety.variety_id
WHERE
winery.region_id = region.region_id
AND
wine.winery_id = winery.winery_id";
if (!empty($wineName)) {
$query .= " AND w.wine_name = '{$wineName}'";
}
if (!empty($wineryName)) {
$query .= " AND winery.winery_name = '{$wineryName}'";
}
// If the user has specified a region, add the regionName
// as an AND clause
if (isset($regionName) && $regionName != "All") {
$query .= " AND region.region_name = '{$regionName}'";
}
// If the user has specified a variety, add the grapeVariety
// as an AND clause
if (isset($grapeVariety) && $grapeVariety != "Riesling") {
$query .= " AND grape_variety.variety = '{$grapeVariety}'";
}

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