Joining over 4 tables - mysql

Here's a fiddle with the schema and a sample query: http://sqlfiddle.com/#!2/573ec4/9
I'm looking to return C.price using I.section and L.level, which are obtained via other joins. When using an inner join with Cost I am left with no result: http://sqlfiddle.com/#!2/573ec4/2
Since cost is a table that maps a section and level to a price, I would like to be able to calculate the price of all the showings in my query

When you are joining to the Cost table you do not include the proper join conditions:
INNER JOIN `cost` `C`
ON `I`.`Section` = c.section -- = c.section is missing
AND `L`.`level` = c.level; -- = c.level is missing
So your full query will be:
SELECT `F`.`date`,
`F`.`time`,
`F`.`tname`,
`I`.`section`,
`L`.`level`,
c.price
FROM `booking_for_schedule` `F`
INNER JOIN `booking_in_seats` `I`
on `F`.`tname`=`I`.`tname`
AND `F`.`booking_num` = `I`.`booking_num`
INNER JOIN `level` `L`
on `F`.`date`=`L`.`date`
AND `F`.`time`=`L`.`time`
AND `F`.`tname`=`L`.`tname`
INNER JOIN `cost` `C`
ON `I`.`Section` = c.section
AND `L`.`level` = c.level;
See SQL Fiddle with Demo

Looks like you're missing some clause on the INNER JOIN cost C (when you are joining on the Cost table).
It should look like this:
INNER JOIN `cost` `C` ON `I`.`Section`=`C`.`Section` AND `L`.`level`=`C`.`level`
instead of:
INNER JOIN `cost` `C` ON `I`.`Section` AND `L`.`level`

You have missed to join the columns. the reason why you have no result is because I.Section AND L.level will always return false.
SELECT F.date,
F.time,
F.tname,
I.section,
L.level,
c.*
FROM booking_for_schedule F
INNER JOIN booking_in_seats I
ON F.tname = I.tname AND
F.booking_num = I.booking_num
INNER JOIN level L
ON F.date = L.date AND
F.time = L.time AND
F.tname = L.tname
INNER JOIN cost C
ON I.Section = C.Section AND -- <<== HERE
L.level = C.level -- <<== HERE
SQLFiddle Demo

Your last line is the problem:
INNER JOIN `cost` `C` ON `I`.`Section` AND `L`.`level`
It should be this:
INNER JOIN `cost` `C` ON `I`.`Section` = `C`.`Section` AND `L`.`level` = `C`.`Level`

Related

Include zero in COUNT with GROUP BY in MySQL

I'm looking to make a query in MySQL to list all the faculties and their number of students given the following table structure:
My query looks like:
SELECT `f`.`id`, `f`.`name`, COUNT(*) `total`
FROM `student` `s`
INNER JOIN `course` `c` ON `c`.`id` = `s`.`course_id`
LEFT JOIN `faculty` `f` ON `f`.`id` = `c`.`faculty_id`
GROUP BY `c`.`faculty_id`
ORDER BY `f`.`name`
And I'm getting this result:
but I need to get all the faculties, even the ones without registered students.
If I use a LEFT JOIN with the course table I get the same results.
If you want all the faculties; your starting table for the JOIN should be the faculty table. Then do Left joins on the other table accordingly.
Use the following query:
SELECT `f`.`id`, `f`.`name`, COUNT(`s`.`id`) AS `total`
FROM `faculty` AS `f`
LEFT JOIN `course` AS `c` ON `f`.`id` = `c`.`faculty_id`
LEFT JOIN `student` AS `s` ON `c`.`id` = `s`.`course_id`
GROUP BY `f`.`id`, `f`.`name`
ORDER BY `f`.`name`
You need to revese the query, your primary tables is faculties (or use right join) :
important - since you want to count cases of zero students you need to treat NULL values that might come up, joining the students table:
SELECT
`f`.`id`, `f`.`name`, SUM(IF(s.id IS NULL, 0,1) `total`
FROM
faculty f
LEFT JOIN course c ON `f`.`id` = `c`.`faculty_id`
LEFT JOIN student s ON `c`.`id` = `s`.`course_id`
GROUP BY `c`.`faculty_id` ORDER BY `f`.`name`

duplicate datas coming in codeigniter left join

SELECT *
FROM `tbl_schedule_task` AS `E`
JOIN `tbl_schedule` AS `S` ON `S`.`schedule_id`=`E`.`schedule_id`
JOIN `tbl_schedule_frequency` AS `F` ON `F`.`frequency_id`=`S`.`frequency_id`
JOIN `tbl_equipments` AS `M` ON `M`.`equipment_id`=`E`.`equipment_id`
LEFT JOIN `tbl_schedule_checklist` AS `L` ON `L`.`check_list_id`=`E`.`check_list_id`
LEFT JOIN `tbl_tech_groups` AS `G` ON `G`.`group_id` = `S`.`shedule_assign_id`
LEFT JOIN `tbl_tech_technicians` AS `T` ON `T`.`techgroup_id`=`G`.`group_id`
LEFT JOIN `tbl_schedule_category` AS `SC` ON `SC`.`category_id`=`S`.`category_id`
JOIN `tbl_site_users` AS `U` ON `U`.`user_id`=`E`.`created_by`
WHERE `E`.`site_id` = '1'
AND (`E`.`approve_flg` =0
AND `E`.`check_out` = 1)
AND `E`.`approve_by` = '2'
ORDER BY `E`.`task_id` DESC
May be inner joins is returning the duplicate data. Check the inner joins before left joins of above query.

LEFT JOIN of only the latest row from a many-to-one

Been banging my head against the wall and cannot solve this :\
SELECT
`people`.*,
`students`.*,
`student_class_relationships`.*,
`geo_checkin_on_campus`.`datetime_created` as checkin_time
FROM `student_class_relationships`
LEFT OUTER JOIN `students`
ON `student_class_relationships`.`student` = `students`.`id`
LEFT OUTER JOIN `people`
ON `students`.`student` = `people`.`id`
LEFT OUTER JOIN `geo_checkin_on_campus`
ON `students`.`id` = (
SELECT MIN(`geo_checkin_on_campus`.`student`)
FROM `geo_checkin_on_campus`
WHERE `geo_checkin_on_campus`.`student` = `students`.`id`
)
WHERE `class` = 56
The expected result is many rows that have only one entry per students.id.
Here is my schema
It is not the best query from performance perspective,
but just to fix your query here is my attempt:
SELECT
`people`.*,
`students`.*,
`student_class_relationships`.*,
geoCheckinOnCampus.datetimeCreated as checkin_time
FROM `student_class_relationships`
LEFT JOIN `students`
ON `student_class_relationships`.`student` = `students`.`id`
LEFT JOIN `people`
ON `students`.`student` = `people`.`id`
LEFT JOIN
(
SELECT
student,
MAX(datetime_created) datetimeCreated
FROM `geo_checkin_on_campus`
GROUP BY `student`
) geoCheckinOnCampus
ON `students`.`id` = geoCheckinOnCampus.`student`
WHERE `class` = 56
Note According to #xQbert answer I would really change MIN to MAX function if you are looking for the latest datetime.
If i assume you want the most recent checkin (and not the earliest created date) for each student in go_checkin_on_Campus then...
SELECT
`people`.*,
`students`.*,
`student_class_relationships`.*,
B.`datetime_Updated` as checkin_time
FROM `student_class_relationships`
LEFT OUTER JOIN `students`
ON `student_class_relationships`.`student` = `students`.`id`
LEFT OUTER JOIN `people`
ON `students`.`student` = `people`.`id`
LEFT OUTER JOIN (
SELECT max(datetime_updated), student
FROM `geo_checkin_on_campus`
group by student
) B
ON `students`.`id` = B.Student
WHERE `class` = 56
NOTE: This is a probable answer. I will edit / modify this according to comments from OP.
This basically does nothing. This is as good as just joining on the student id
LEFT OUTER JOIN `geo_checkin_on_campus`
ON `students`.`id` = (
SELECT MIN(`geo_checkin_on_campus`.`student`)
FROM `geo_checkin_on_campus`
WHERE `geo_checkin_on_campus`.`student` = `students`.`id`
)
If you want the min (or earliest) datetime_created use something like
LEFT OUTER JOIN (
SELECT `geo_checkin_on_campus`.`student` student,
MIN(`geo_checkin_on_campus`.`datetime_created`) dt
FROM `geo_checkin_on_campus`
WHERE `geo_checkin_on_campus`.`student` = `students`.`id`
GROUP BY `geo_checkin_on_campus`.`student`
) t
ON `students`.`id` = t.student

MySQL: CASE outside JOIN

I have a table where I want to do different joins based on the value of a field in the source table. This is my current attempt:
SELECT i.name, c.name, loc.name FROM `item` i
CASE WHEN (i.loc_exception IS NOT NULL) THEN (
JOIN `location_exceptions` le ON i.loc_exception = le.id
JOIN `location` loc ON le.id_location = loc.id
JOIN `city` c ON loc.`id_city` = c.id
) ELSE (
JOIN `location` loc ON i.`id_location` = loc.id
JOIN `city` c ON i.`id_city` = c.id
)
WHERE i.id = 5
Is it even possible to use CASE as I've attempted here? If not, is there any other way I can achieve what I want?

Merging columns in INNER/LEFT JOIN returns NULL values?

I'm facing an issue where I have several tables joined, but I need to combine the e.url and f.url_new columns. Otherwise, the result is as expected. Here is my query.
SELECT a.`added_date`,b.`type`,c.`action`,e.`url`,f.`url_new`
FROM `websites_submitted_main` a
INNER JOIN `websites_submitted_type` b ON a.`type_id` = b.`type_id`
INNER JOIN `websites_submitted_action` c ON a.`action_id` = c.`action_id`
INNER JOIN `users` d ON a.`user_id` = d.`user_id`
LEFT JOIN `websites` e ON a.`url_id` = e.`id`
LEFT JOIN `websites_submitted_new` f ON a.`url_new_id` = f.`url_new_id`
WHERE a.`user_id` = 1 ORDER BY a.`added_date` DESC
I've tried CONCAT, but the column contained all NULL values. Here's that query.
SELECT a.`added_date`,b.`type`,c.`action`,CONCAT(e.`url`,f.`url_new`) AS url
FROM `websites_submitted_main` a
INNER JOIN `websites_submitted_type` b ON a.`type_id` = b.`type_id`
INNER JOIN `websites_submitted_action` c ON a.`action_id` = c.`action_id`
INNER JOIN `users` d ON a.`user_id` = d.`user_id`
LEFT JOIN `websites` e ON a.`url_id` = e.`id`
LEFT JOIN `websites_submitted_new` f ON a.`url_new_id` = f.`url_new_id`
WHERE a.`user_id` = 1 ORDER BY a.`added_date` DESC
Is there a minor modification I can make to this query to merge these columns?
try using CONCAT_WS() instead of CONCAT()
SELECT `CONCAT_WS(' ',e.url, f.url_new )` ....
CONCAT_WS() will concatenate the values if the values are not null.
From the manual of CONCAT()
CONCAT() returns NULL if any argument is NULL.
SELECT a.`added_date`,b.`type`,c.`action`,CONCAT_WS("", e.`url`,f.`url_new`) AS url
FROM `websites_submitted_main` a
INNER JOIN `websites_submitted_type` b ON a.`type_id` = b.`type_id`
INNER JOIN `websites_submitted_action` c ON a.`action_id` = c.`action_id`
INNER JOIN `users` d ON a.`user_id` = d.`user_id`
LEFT JOIN `websites` e ON a.`url_id` = e.`id`
LEFT JOIN `websites_submitted_new` f ON a.`url_new_id` = f.`url_new_id`
WHERE a.`user_id` = 1 ORDER BY a.`added_date` DESC