Mysql complex query to join - php

I need some help to JOIN the queries below, because I believe this is super heavy, While loops inside other while loops... a mess, right?! :(
This works, but if someone could help to JOIN this into one query only:
$query_1 = mysql_query("SELECT * FROM booking_reservation WHERE reservation_confirmed = '1' AND (reservation_name LIKE '$data%' OR reservation_phone LIKE '$data%' OR reservation_email LIKE '$data%')");
while ($row = mysql_fetch_array($query_1)) {
$calendar_id = $row['calendar_id'];
$query_2 = mysql_query("SELECT * FROM booking_calendars WHERE calendar_id = '$calendar_id'");
$row_2 = mysql_fetch_array($query_2);
$slot_id = $query_1['slot_id'];
$query_3 = mysql_query("SELECT * FROM booking_slots WHERE slot_id = '$slot_id'");
while ($row_3 = mysql_fetch_array($query_3)) {
echo '<tr><td>' . htmlentities($row2['slot_date']) . '</td><td>' . htmlentities($query_3['slot_time_from']) . '</td><td>' . htmlentities($query_1['reservation_name']) . '</td><td>' . htmlentities($query_3['calendar_title']) . '</td><td>' . htmlentities($query_1['reservation_phone']) . '</td><td>' . htmlentities($query_1['reservation_email']) . '</td></tr>';
}
}

One of these should be what you want, you use INNER JOIN if you want to get reservations that only exist in booking_calendars, and booking_slots, or LEFT JOIN if you want all reservations regardless if they exist in the other tables
Inner join:
SELECT * FROM booking_reservation br
INNER JOIN booking_calendars bc ON br.calendar_id=bc.calendar_id
INNER JOIN booking_slots bs ON br.slot_id=bs.slot_id
WHERE br.reservation_confirmed = '1'
AND (br.reservation_name LIKE '$data%'
OR br.reservation_phone LIKE '$data%'
OR br.reservation_email LIKE '$data%')
Left join:
SELECT * FROM booking_reservation br
LEFT JOIN booking_calendars bc ON br.calendar_id=bc.calendar_id
LEFT JOIN booking_slots bs ON br.slot_id=bs.slot_id
WHERE br.reservation_confirmed = '1'
AND (br.reservation_name LIKE '$data%'
OR br.reservation_phone LIKE '$data%'
OR br.reservation_email LIKE '$data%')
1 important note, using SELECT * isn't recommended, it is much better to tell mysql which columns you need from each of the tables, or from the table you're selecting from.
N.B.: You should listen to what Raptor said, mysql_* functions are deprecated and will be removed in later php versions, you should start using PDO or mysqli

Try with this i hope this query will works for you
select * from booking_reservation br
join booking_calendars bc ON br.calendar_id=bc.calendar_id
join booking_slots bs ON bc.slot_id=bs.slot_id
where br.reservation_confirmed='1'
AND br.(reservation_name LIKE '$data%' OR br.reservation_phone LIKE '$data%' OR br.reservation_email LIKE '$data%')

Related

left join outputs incorrect first block of data

I'm trying to get data from two tables: users and posts using left join.
$items = '';
$sql = "
SELECT u.id as uid
, u.name as uname
, p.id as pid
, p.date as pdate
, p.title as ptitle
, p.user as puser
FROM users u
LEFT
JOIN posts p
ON u.id = p.user
WHERE u.role = 'mod'
GROUP
BY p.title;";
$stmt = $db->query($sql);
while($row = $stmt->fetch()){
$date = strtotime($row['pdate']);
$date = date("d-m-Y", $date);
$items.= "<div class='itemp' data-id=" . $row['pid'] . " data-user='" . $row['uname'] . "'>" .
"<span class='spandate'>" . $date . "</span>" .
"<span class='spantitle'>" . $row['ptitle'] . "</span>" .
"<span class='spanuser'>" . $row['uname'] . "</span>" .
"</div>\n";
}
echo $items;
Output is ok except first row where I see the date - 1.1.1970 - but there is no any row in posts with that date. Plus - in the same row ptitle is missing.
Also, is there a better way to create this query, avoiding as keyword ?
desired output (single block):
<div class='itemp' data-id=116 data-user='JOHN SMITH'><span class='spandate'>01-12-2017</span><span class='spantitle'>BLUE SKY</span><span class='spanuser'>JOHN SMITH</span></div>
Also, is there a better way to create this query, avoiding as keyword ?
Yes (but not better in my opinion):
SELECT users.id,
users.name,
posts.id,
posts.date,
posts.title,
posts.user
FROM users
LEFT
JOIN posts
ON users.id = posts.user
WHERE users.role = 'mod'
GROUP
BY posts.title;
But as mentioned in the comments you have to modify your while loop in this case to get access to your values. But I think this is not a better way of writing this query cause it makes it harder to read.
Regarding your JOIN problem. this depends on what your result should be (I guess you only want users with posts ). So you should take a look at INNER JOIN instead of LEFT JOIN. You will get only results which also have posts entrys.
Due to the nature of LEFT JOIN all entrys on the left table (in your case users) will be used, even if they donĀ“t have an entry in the posts table.
INNER JOIN will only return results which match results in both tables.

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 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

How can I improve the following mysql selects?

I am currently refactoring a legacy application and converting piece by piece over to zend framework 1.12.
I am scratching my head as to how to convert this over to zend db, is there a way that this can be done in one query?
Right now I see that it fetches a list of folders first and then runs an additional query per folder...
Running this as one query will improve performance, right?
$folders_query = DB::Query("select * from contacts_folders order by sort_order, name");
while($folders = DB::FetchArray($folders_query)){
$counts_total = DB::QueryOne("SELECT count(cm.messages_id) AS total
FROM contacts_basics cb, contacts_messages cm
WHERE cb.contacts_id = cm.contacts_id
AND cm.folders_id = '" . $folders['folders_id'] . "'
AND cm.status = '1'
AND cm.mark = '0'");
if ($counts_total >0){
$folders_name = '<strong>' . $folders['name'] . ' (' . $counts_total . ')</strong>';
} else {
$folders_name = $folders['name'];
}
echo '<li><a href="messages.php?fID=' . $folders['folders_id'] . '">';
echo $folders_name;
echo '</a></li>';
}
Yes, you can do both in the same query
SELECT cf.*, count(cm.messages_id) AS total
FROM contacts_folders cf left outer join
contacts_messages cm
on cf.id = cm.folders_id and
cm.status = '1' AND cm.mark = '0' left outer join
contacts_basics cb
on cb.contacts_id = cm.contacts_id
group by cf.folders_id
order by cf.sort_order, cf.name;
This uses a left outer join to be sure that you get all folders, even if there are no messages (which is how the original code works). Because of the left outer join, the conditions need to be moved into on clauses.
It also fetches all the information from the folders as well as the total. If there are no messages, then it should return 0 for that folder.
There was a minor bug in Gordon's answer but I figured it out thanks to him.
I changed
contacts_basics cb left outer join
To:
left outer join contacts_basics cb
The following code works as expected:
public function getMenuCounts(){
$raw = "SELECT cf.*, count(cm.messages_id) AS total
FROM contacts_folders cf left outer join
contacts_messages cm
on cf.folders_id = cm.folders_id and
cm.status = '1' AND cm.mark = '0'
left outer join contacts_basics cb
on cb.contacts_id = cm.contacts_id
group by cf.folders_id
order by cf.sort_order, cf.name;";
$db = Zend_Db_Table::getDefaultAdapter();
$stmt = $db->query($raw);
return $stmt->fetchAll();
}

SQL JOIN query not displaying anything- PHP

I am doing a sql query but it is not returning any data from the tables. I am not sure why, I have changed from INNER to LEFT but no luck. I have revised the query several times but i cant find an issue. Any thoughts of why I am not getting anything displayed?
TABLE STRUCTURE
TABLE CREATE QUERY
PHP
$query = ("SELECT class.class_name, class.class_caption, class.class_credit_hours, class.class_description, faculty_fname, faculty_lname
FROM class
LEFT JOIN section
ON class.id = section.class_id
LEFT JOIN faculty
ON faculty.id = section.faculty_id OR faculty.id = office_hours.faculty_id
LEFT JOIN faculty_titles
ON faculty_titles.faculty_id = faculty.id
LEFT JOIN faculty_education
ON faculty_education.faculty_id = faculty.id
LEFT JOIN major_class_br
ON major_class_br.class_id = class.id
LEFT JOIN major_minor
ON major_class_br.major_minor_id = major_minor.id
LEFT JOIN sched_sect_br
ON sched_sect_br.section_id = section.id
LEFT JOIN schedule
ON schedule.id = sched_sect_br.schedule_id
LEFT JOIN semester
ON semester.id = schedule.semester_id
LEFT JOIN office_hours
ON schedule.id = office_hours.schedule_id AND faculty.id = office_hours.faculty_id
");
//execute query
$result = mysql_query($query);
if ($result){
$totalhours = 0;
while ($row = mysql_fetch_assoc( $result ))
{
print "<b>" . $row['class_name'] . "</b><br>";
print $row['class_caption'] . "<br>";
print $row ['class_credit_hours'] . "hrs. <br>";
print $row ['faculty_lname'] . "hrs. <br>";
print $row ['faculty_fname'] . "hrs. <br>";
print $row['class_description'] . "<br>";
print "------------------------------<br />";
$totalhours += $row['class_credit_hours'];
}
}
print "<p>Total hours for Major: " . $totalhours . ".</p>";
Desired display:
Computer Programming I
CP1000
4
James Doe
This course offers introduction to programming.
UPDATE: The issue was found here but I am not sure why
ON faculty.id = section.faculty_id OR faculty.id = office_hours.faculty_id
Copy the SQL, go to MySQL admin, execute the SQL there and see if it returns any results.
Remove all the JOIN and execute again, you should see at least something
Add the JOIN one by one
Try to identify which JOIN resulted in no rows being returned
Check the left and right hand side of that join and ensure there actually are valid data to join
Alternatively use OUTER JOIN

Categories