mySQl, Query: How to customize selection from database? - php

I have four tables:
courses, allocate_rooms, rooms, departments
Query:
SELECT
courses.`name`,
courses.`code`,
allocate_rooms.`start`,
allocate_rooms.`end`,
rooms.room_number
FROM
departments
JOIN courses ON departments.id = courses.department_id
LEFT JOIN allocate_rooms ON allocate_rooms.course_id = courses.id
LEFT JOIN rooms ON allocate_rooms.room_id = rooms.id
WHERE
departments.id = 1
From the Query I have to make a selection view as rooms.room_number, allocate_rooms.start-allocate.rooms_end; and if there is no data related to that course I have to show "Not Scheduled Yet".
Eg: R.No: 301,12:00-12:30; (if the course related data is there otherwise it will show "Not Scheduled Yet"
How do I rewrite the above Query? If anybody help me to find the solution.

I'm not sure if it's what you need, but try this:
You can use DECODE for getting what you need.
SELECT
c.name name
,c.code code
,decode(ar.start,NULL,'Not Schedule Yet') START
,decode(ar.end,NULL,'Not Schedule Yet') END
,r.room_number roomnum
FROM
departments d
,courses c
,allocate_rooms ar
,rooms r
WHEREd.id = c.id
AND ar.course_id = c.id
AND ar.room_id = r.room_id
AND d.id = 1;

You can try with ifnull
SELECT courses.name, courses.code, allocate_rooms.start,
allocate_rooms.end ,
case rooms.room_number
WHEN IS NULL THEN 'No Rooms allocated'
WHEN 0 THEN 'No Rooms allocated'
ELSE room.room_number
end
FROM departments
join courses on departments.id = courses.department_id
left join allocate_rooms on allocate_rooms.course_id=courses.id
left join rooms on allocate_rooms.room_id=rooms.id
WHERE departments.id=1

Here is the solution:
SELECT courses.name, courses.code,COALESCE( CONCAT('R. No',':',rooms.room_number,', ',days.name ,', ', allocate_rooms.start,' - ',allocate_rooms.end),"Not Assigned Yet") AS Schedule
FROM departments join courses on departments.id = courses.department_id
left join allocate_rooms on allocate_rooms.course_id=courses.id
left join rooms on allocate_rooms.room_id=rooms.id
left join days on allocate_rooms.day_id=days.id WHERE departments.id=1

Related

How to perform inner join in mysql

I have to write a query such that ,I need to get events whose start date is of 30 min from now.
My conditions are:
1) get the event from events table
2)Join created by of events with id in users table.
3)Comments from comment table with user ser id
But the problem here is if there is no comment for event then the event it self is not coming.If any comment is present it is coming.I dont want this.If comment is not there just fetch it as empty but not hide the total event .Can anyone please help me,.Thanks.
select u.email ,group_members.user_id,users.first_name,u.first_name
as host_name,events.name,events.start_date,comments.comments,c.first_name as
comment_user,comments.id from events
inner join users as u on u.id = events.created_by
inner join comments on events.id = comments.event_id
inner join group_members on events.group_id = group_members.group_id
inner join users as c on comments.from_user = c.id
inner join users on group_members.user_id = users.id
where events.start_date between date_add(now(),interval 1 minute) and date_add(
now(),interval 30 minute)
and group_members.user_status = 2
and events.status = 2
You need a left join to the comments table. I would put that table last in the from clause.
select u.email, gm.user_id, gu.first_name, u.first_name as host_name,
e.name, e.start_date, c.comments, uc.first_name as comment_user,
c.id
from events e inner join
users u
on u.id = e.created_by inner join
group_members gm
on e.events.group_id = gm.group_id inner join
users gu
on gm.user_id = gu.id left join
comments c
on e.id = c.event_id left join
users uc
on c.from_user = uc.id
where e.start_date between date_add(now(),interval 1 minute) and date_add(now(),interval 30 minute) and
gm.user_status = 2 and
e.status = 2;
Once you use a left join on comments, you also need a left join for the from user. I replaced all table names with aliases -- this makes it easier to track which table is used for which purpose.
Use the INNER JOIN Keyword and select the two columns by putting them with keyword ON.
SELECT EMP.EMP_ID, EMP.EMP_NAME, DEPT.DEPT_NAME FROM EMP
INNER JOIN DEPT ON DEPT.DEPT_ID = EMP.DEPT_ID;

Combine two MySql into one query

I have two sql queries that I need to combine into one query for better efficiency, just not sure how to do it. Basically I need to query my Supplier, then for each supplier check to see if the Listing table has more than one record that matches based upon "supplier id", if it does then I need to return the supplier name and id. Here are my two queries:
Query 1:
SELECT s.name, s.id
FROM Supplier s
Query 2:
SELECT l.asin,
l.id,
COUNT(*) c
FROM Listing l
LEFT JOIN Product p
ON p.id = l.product_id
LEFT JOIN Supplier s
ON p.supplier_id = s.id
WHERE (l.matchValidated IS NULL OR l.matchValidated = 0)
AND s.id = SUPPLIER_ID_GOES_HERE
GROUP BY l.asin HAVING c > 1);
You already have supplier joined in the second query so you just need to add the supplier name and id to your SELECT and GROUP BY.
SELECT l.asin,
l.id,
s.name AS supplier_name,
s.id AS supplier_id,
COUNT(*) c
FROM Listing l
LEFT JOIN Product p
ON p.id = l.product_id
LEFT JOIN Supplier s
ON p.supplier_id = s.id
WHERE (l.matchValidated IS NULL OR l.matchValidated = 0)
GROUP BY l.asin, l.id, s.name, s.id
HAVING c > 1;

mysql join return 0 for one column with other columns intact

I wish to join multiple tables like- Categories, menus, restaurants, reviews, etc.
to return the restaurants that provide the inserted food with their prices.
Everything works except numberOfReviews in reviews table.
If a restaurant has no reviews then output should be 0 for numOfReviews column but other column values should be retrieved i.e. price, name, etc.
With following query I get all fields as null and count(numReviews) as 0:
select r.id
,r.`Name`
,r.`Address`
,r.city
,r.`Rating`
,r.`Latitude`
,a.`AreaName`
,m.`Price`
,count(rv.id)
from `categories` c, `menus` m, `restaurants` r, areas a, reviews rv
where m.`ItemName`="tiramisu"
and c.`restaurant_id`=r.`id`
and m.`category_id`=c.id
and r.`AreaId`=a.`AreaId`
and if I can't match rv.restaurant_id=r.id in where clause(obviously).
Where am I getting wrong? How do I solve this?
edited
select r.id,
r.`Name`,
r.`Address`,
r.city,
r.`Rating`,
r.`Latitude`,
a.`AreaName`,
m.`Price`,
r.`Longitude`,
r.Veg_NonVeg,
count(rv.id)
from restaurants r LEFT JOIN `reviews` rv on rv.`restaurant_id`=r.`id`
inner join `categories` c on c.`restaurant_id` = r.id
inner join `menus` m on m.`category_id` = c.id
inner join `areas` a on a.`AreaId` = r.`AreaId`
where m.`ItemName`="tiramisu"
First of all, don't use this old school syntax for the jointures.
Here is a query that may solve your problem:
SELECT R.id
,R.Name
,R.Address
,R.city
,R.Rating
,R.Latitude
,R.Longitude
,A.AreaName
,M.Price
,R.Veg_NonVeg
,COUNT(RV.id) AS numOfReviews
FROM restaurants R
INNER JOIN categories C ON C.restaurant_id = R.id
INNER JOIN menus M ON M.category_id = C.id
INNER JOIN areas A ON A.AreaId = R.AreaId
LEFT JOIN reviews RV ON RV.restaurant_id = R.id
WHERE M.ItemName = 'tiramisu'
GROUP BY R.id, R.Name, R.Address, R.city, R.Rating, R.Latitude, R.Longitude, A.AreaName, M.Price, R.Veg_NonVeg
I used explicit INNER JOIN syntax instead of your old school syntax and I modified the jointure with table reviews in order to get the expected result. The GROUP BY clause is required to use the aggregate function COUNT, every rows will be grouped by the enumerated columns (every column except the one used by the function).
Here is another solution that simplify the GROUP BY clause and allow the modification of SELECT statement without having to worry about the fact that every columns need to be part of the GROUP BY clause:
SELECT R.id
,R.Name
,R.Address
,R.city
,R.Rating
,R.Latitude
,R.Longitude
,A.AreaName
,M.Price
,R.Veg_NonVeg
,NR.numOfReviews
FROM restaurants R
INNER JOIN (SELECT R2.id
,COUNT(RV.id) AS numOfReviews
FROM restaurants R2
LEFT OUTER JOIN reviews RV ON RV.restaurant_id = R2.id
GROUP BY R2.id) NR ON NR.id = R.id
INNER JOIN categories C ON C.restaurant_id = R.id
INNER JOIN menus M ON M.category_id = C.id
INNER JOIN areas A ON A.AreaId = R.AreaId
WHERE M.ItemName = 'tiramisu'
As you can see here I added a new jointure on a simple subquery that does the aggregation job in order to provide me the expected number of reviews for each restaurant.
Hope this will help you.

MySql Join Query left join

I have table name students having fields student_id, house_id etc..
and subjects, houses, students_subjects
I am using this query
SELECT students_subjects.student_id,students.house_id,students_subjects.subject_id,subjects.subject_name,students.rollno,students.first_name, students.last_name FROM
students_subjects LEFT JOIN students on students_subjects.student_id=students.id
LEFT JOIN subjects on students_subjects.subject_id=subjects.id WHERE students_subjects.class_years_section_id=1
This is working fine for me ..
Now i want to get house name too from houses table
I tried this query
SELECT students_subjects.student_id,students.house_id,houses.house_name, students_subjects.subject_id,subjects.subject_name,students.rollno,students.first_name, students.last_name FROM
students_subjects LEFT JOIN students on students_subjects.student_id=students.id
LEFT JOIN subjects on students_subjects.subject_id=subjects.id
LEFT JOIN houses on students.house_id=houses.id
WHERE students_subjects.class_years_section_id=1
AND students_subjects.school_session_id=1 AND students.is_active=1
and it gives me house_name = NULL
Can anybody tell me how to get house name too . using join query
Thanks
The error in your query is caused by the LEFT JOIN keyword that is after WHERE clause,
SELECT students_subjects.student_id,
students.house_id,
students_subjects.subject_id,
subjects.subject_name,
students.rollno,
students.first_name,
students.last_name
FROM students_subjects
LEFT JOIN students
on students_subjects.student_id=students.id
LEFT JOIN subjects
on students_subjects.subject_id=subjects.id
LEFT JOIN houses
on students.house_id=houses.id
WHERE students_subjects.class_years_section_id = 1 AND
students_subjects.school_session_id = 1 AND
students.is_active = 1
Remember that JOINs are part of the FROM Clause.
UPDATE 1
SELECT b.student_id,
a.house_id,
b.subject_id,
c.subject_name,
a.rollno,
a.first_name,
a.last_name,
d.house_name
FROM students a
INNER JOIN students_subjects b
ON b.student_id = a.id
INNER JOIN subjects c
ON b.subject_id = c.id
INNER JOIN houses d
ON a.house_id = d.id
WHERE b.class_years_section_id = 1 AND
b.school_session_id = 1 AND
a.is_active = 1
You've miss placed the WHERE clause, try this:
SELECT students_subjects.student_id,students.house_id,students_subjects.subject_id,subjects.subject_name,students.rollno,students.first_name, students.last_name
FROM students_subjects
LEFT JOIN students ON students_subjects.student_id=students.id
LEFT JOIN subjects ON students_subjects.subject_id=subjects.id
LEFT JOIN houses ON students.house_id=houses.id
WHERE students_subjects.class_years_section_id=1
AND students_subjects.school_session_id=1 AND students.is_active=1

3 table left outer join doesn't work with subquery

A brief description... I have 4 tables. "contacts" (a list of each person, unique IDs), contact_phones (multiple telephone numbers for each contact, joins on contact_id), and contact_communication (each time we've spoken to this contact, joins on contact_id), and schools (a list of schools, joins schools.school_id = contacts.contact_id).
What I need: I need to look up an individual school. For that school, I need a list of each person that goes there, their main telephone number, and the last communication we had with them (if any).
The problem is, if we have had NO communication with them, they don't show up in the list. If I take out the "AND" statement in the "WHERE" clause, then I get more than one communication record. I only want the latest communication record, but I want all the contacts. Some contacts don't have a communication record though.
This is my query:
SELECT c.id,
c.f_name,
c.l_name,
c.address1,
c.address2,
c.city,
c.state,
c.zip,
c.tel,
c.school_id,
c.email,
ct.tel,
cc.date,
cc.reason,
cc.result,
cc.caller
FROM contacts AS c
LEFT OUTER JOIN contact_phones AS ct ON c.id = ct.contact_id
LEFT OUTER JOIN contact_communication AS cc ON c.id = cc.contact_id
WHERE school_id = '$schoolId' AND
cc.id IN (SELECT MAX(id) FROM contact_communication WHERE contact_id = c.id)
ORDER BY cc.date DESC
The problem is, this query gives me only the latest communication (which is all I want) but won't list contacts that have no communication.
I've been at this for 3 days. Any tips?
Thanks!!
(PS: I'll edit and give more info if needed.)
EDIT
The answer (thank you, ysrb) is changing my where clause:
SELECT c.id,
c.f_name,
c.l_name,
c.address1,
c.address2,
c.city,
c.state,
c.zip,
c.tel,
c.school_id,
c.email,
ct.tel,
cc.date,
cc.reason,
cc.result,
cc.caller
FROM contacts AS c
LEFT OUTER JOIN contact_phones AS ct ON c.id = ct.contact_id
LEFT OUTER JOIN contact_communication AS cc ON c.id = cc.contact_id
WHERE school_id = '$schoolId' AND
(cc.id IN (SELECT MAX(id) FROM contact_communication WHERE contact_id = c.id) OR cc.id IS NULL)
ORDER BY cc.date DESC
Try:
SELECT c.id,
c.f_name,
c.l_name,
c.address1,
c.address2,
c.city,
c.state,
c.zip,
c.tel,
c.school_id,
c.email,
ct.tel,
cc.date,
cc.reason,
cc.result,
cc.caller
FROM contacts AS c
LEFT OUTER JOIN contact_phones AS ct ON c.id = ct.contact_id
LEFT OUTER JOIN contact_communication AS cc ON c.id = cc.contact_id
WHERE school_id = '$schoolId' AND
(cc.id = (SELECT MAX(id) FROM contact_communication WHERE contact_id = c.id) OR cc.ID IS NULL)
ORDER BY cc.date DESC

Categories