Appending new fields from another JOIN statements in MySQL query - mysql

So, I have 3 tables :
guest :
id_guest | name
1 | John
2 | Nick
3 | James
4 | Paul
5 | Chris
6 | Karen
7 | Peter
room :
id_room | status
1 | Clean
2 | Dirty
3 | Dirty
4 | Clean
5 | Clean
6 | Clean
reservation :
id_guest | id_room | date
1 | 1 | 2015-04-15
1 | 1 | 2015-04-16
1 | 1 | 2015-04-17
2 | 3 | 2015-04-15
3 | 4 | 2015-04-15
3 | 4 | 2015-04-16
4 | 2 | 2015-04-16
5 | 2 | 2015-04-17
6 | 2 | 2015-04-18
And this is what the expected output should be :
id_room | status | d04-15 | d04-16 | d04-17 | d04-18
1 | Clean | John | John | John |
2 | Dirty | | Paul | Chris | Karen
3 | Dirty | Nick | | |
4 | Clean | James | James | |
5 | Clean | | | |
6 | Clean | | | |
I have been able to show it until the third field (d04-15) though with the date as values, using :
SELECT room.id_room,
room.status,
reservation.date AS d04-15
FROM room
LEFT JOIN reservation
ON room.id_room = reservation.id_room AND reservation.date = '2015-04-15'
GROUP BY room.id_room
But I'm not sure as to how to display the name there and
appending new fields (d04-16, d04-17, and d04-18) from another JOIN statement.
Any help would be appreciated. Thanks.

The columns returned in a query can't be altered at run time; they have to be statically declared in the SQL SELECT statement.
Here's an example of a statement that can achieve the specified result:
SELECT m.id_room
, m.status
, MAX(IF(r.date='2015-04-15',g.name,NULL)) AS `d04-15`
, MAX(IF(r.date='2015-04-16',g.name,NULL)) AS `d04-16`
, MAX(IF(r.date='2015-04-17',g.name,NULL)) AS `d04-17`
, MAX(IF(r.date='2015-04-18',g.name,NULL)) AS `d04-18`
FROM room m
LEFT
JOIN reservation r
ON r.id_room = m.id_room
AND r.date IN ('2015-04-15','2015-04-16','2015-04-17','2015-04-18')
LEFT
JOIN guest g
ON g.id_guest = r.id_guest
GROUP BY m.id_room

Related

Mysql returning incorrect COUNT when using more than one JOIN?

I have 3 tables: NAMES, REGISTRATIONS, and RENEWALS. I'm using LEFT JOIN to join the 3 tables with a common ID.
I need to count the number of REGISTRATIONS of each user, as well as the number of RENEWALS. I've tried using different options in the GROUP BY field, but none seemed to work.
Here's the SELECT statement:
SELECT
names.name_id AS 'Names ID'
,names.name AS Name
,count(registrations.date) AS Registrations
,count(renewals.date) AS Renewals
FROM names
LEFT JOIN registrations
ON names.name_id = registrations.name_id
LEFT JOIN renewals
ON renewals.name_id = registrations.name_id
GROUP BY names.name_id, registrations.name_id, renewals.name_id;
And here are the 3 tables:
TABLE: names
+---------+------+
| name_id | name |
+---------+------+
| 1 | Ana |
| 2 | John |
| 3 | Paul |
+---------+------+
TABLE: registrations
+-----------------+---------+---------------------+-------+
| registration_id | name_id | date | value |
+-----------------+---------+---------------------+-------+
| 1 | 1 | 2014-01-30 13:15:02 | 15 |
| 2 | 2 | 2014-05-01 18:01:44 | 15 |
| 3 | 2 | 2014-07-08 15:10:43 | 20 |
| 4 | 3 | 2012-09-28 17:45:32 | 15 |
| 5 | 3 | 2014-01-09 18:26:14 | 20 |
| 6 | 3 | 2015-01-10 13:22:01 | 25 |
+-----------------+---------+---------------------+-------+
TABLE: renewals
+------------+---------+---------------------+-------+
| renewal_id | name_id | date | value |
+------------+---------+---------------------+-------+
| 1 | 1 | 2015-01-30 00:00:00 | 5 |
| 2 | 1 | 2016-02-12 00:00:00 | 5 |
| 3 | 1 | 2015-06-01 00:00:00 | 5 |
| 4 | 1 | 2013-11-24 00:00:00 | 5 |
| 5 | 2 | 2015-01-27 00:00:00 | 5 |
+------------+---------+---------------------+-------+
Here's the INCORRECT result I'm getting:
+----------+------+---------------+----------+
| Names ID | Name | Registrations | Renewals |
+----------+------+---------------+----------+
| 1 | Ana | 4 | 4 |
| 2 | John | 2 | 2 |
| 3 | Paul | 3 | 0 |
+----------+------+---------------+----------+
The CORRECT result I was expecting would be:
+----------+------+---------------+----------+
| Names ID | Name | Registrations | Renewals |
+----------+------+---------------+----------+
| 1 | Ana | 1 | 4 |
| 2 | John | 2 | 1 |
| 3 | Paul | 3 | 0 |
+----------+------+---------------+----------+
How can I fix the query to get a correct result?
Try this:
SELECT
names.name_id AS 'Names ID'
,names.name AS Name
,count(distinct registrations.registration_id) AS Registrations
,count(distinct renewals.renewal_id) AS Renewals
FROM names
LEFT JOIN registrations
ON names.name_id = registrations.name_id
LEFT JOIN renewals
ON renewals.name_id = registrations.name_id
GROUP BY names.name_id, registrations.name_id, renewals.name_id;
Whenever I run into this type of issue, I find it helps to just run a select * query if your server can take it. Like this:
SELECT *
FROM names
LEFT JOIN registrations
ON names.name_id = registrations.name_id
LEFT JOIN renewals
ON renewals.name_id = registrations.name_id ;
That will let you see what you are really counting.
Your query is executed just fine.
After the first join you have 1 entry for Ana, 2 entries for John and 3 for Paul.
After the seconds join the one entry for Ana is duplicated 4 times and joined (concatenated) with the 4 renewals. If you now count the registration dates for Ana you get 4. That is where your "errors" come from.
You could for example count the distinct dates to fix it.

Pulling latest values using distinct and max

I have a table that looks like this if I 'select *'
+----+--------+------+------------+
| id | name | task | day |
+----+--------+------+------------+
| 1 | Rodney | 2 | 2016-05-05 |
| 2 | Rodney | 2 | 2016-05-08 |
| 3 | Rodney | 8 | 2016-05-08 |
| 4 | Scott | 2 | 2016-05-05 |
| 5 | Scott | 8 | 2016-05-05 |
| 6 | Frank | 2 | 2016-05-05 |
| 7 | Frank | 2 | 2016-05-08 |
+----+--------+------+------------+
What I'm trying to achive is a query that will get the last entered 'task' for each person. So, in this case I would want back:
2 | Rodney | 2 | 2016-05-08
3 | Rodney | 8 | 2016-05-08
4 | Scott | 2 | 2016-05-05
5 | Scott | 8 | 2016-05-05
7 | Frank | 2 | 2016-05-08
I'm pretty sure I need to use distinct against name & task and max for the most recent entry. Just not sure how to structure the two of them together to get the result.
select distinct name, task from test;
Gets me close...
+--------+------+
| name | task |
+--------+------+
| Rodney | 2 |
| Rodney | 8 |
| Scott | 2 |
| Scott | 8 |
| Frank | 2 |
+--------+------+
But no date...My SQL is limited. Any help would be appreciated.
Aggregate your rows so as to get the latest day per name. Then access the table again to get the records matching thse days:
select *
from test
where (name, day) in
(
select name, max(day)
from test
group by name
);
Another way is to select the records for which not exists a later record for the same name:
select *
from test
where not exists
(
select *
from test later
where later.name = test.name
and later.day > test.day
);

MySQL GROUP By Only when Two column matches

I am trying to group a record only if two of the fields repeat themselves.
I am designing a social sharing photo app. users can share, like and comment on thers photo. Each action (share, comment, like) will appear on their friends wall.
The Problem is that when a user do all the three actions, the picture appears three times instead of one with the three action on it.
Data in database is like this (activities_tb)
id | photoID | uiID | action | date
-------------------------------------------
1 | 1 | 2 | like | 01/01/2015
2 | 1 | 2 | share | 02/01/2015
3 | 1 | 4 | share | 03/01/2015
4 | 1 | 2 | comment | 04/01/2015
5 | 2 | 4 | like | 04/01/2015
6 | 2 | 2 | like | 05/01/2015
7 | 2 | 3 | share | 05/01/2015
8 | 2 | 4 | comment | 06/01/2015
8 | 3 | 3 | like | 07/01/2015
9 | 3 | 5 | like | 08/01/2015
10 | 3 | 5 | comment | 08/01/2015
The query result I want to get
id | photoID | uiID | action | date
-------------------------------------------
3 | 1 | 4 | share | 03/01/2015
4 | 1 | 2 | comment | 04/01/2015
6 | 2 | 2 | like | 05/01/2015
7 | 2 | 3 | share | 05/01/2015
8 | 2 | 4 | comment | 06/01/2015
8 | 3 | 3 | like | 07/01/2015
10 | 3 | 5 | comment | 08/01/2015
This is my statement
SELECT id, photoID, uiID, action, date
FROM activities_tb
GROUP BY photoID, uiID.
This combines all the photos by their id returning only three results
I will be glad if anyone can be of help, thank you
You can first select required ids and join on your table:
select tb.*
from activities_tb tb
join(select max(id) as id
from activities_tb
group by photoID, uiID) t on t.id = tb.id
You are looking for "SELECT DISTINCT"
SELECT DISTINCT photoID, uiID, action, date
FROM activities_tb
GROUP BY photoID, uiID.

MySql query to perform join between 2 tables

These are the tables:
professor
+-------+--------+--------+--------+------+
| empid | name | status | salary | age |
+-------+--------+--------+--------+------+
| 1 | Arun | 1 | 2000 | 23 |
| 2 | Benoy | 0 | 3000 | 25 |
| 3 | Chacko | 1 | 1000 | 36 |
| 4 | Divin | 0 | 5000 | 32 |
| 5 | Edwin | 1 | 2500 | 55 |
| 7 | George | 0 | 1500 | 46 |
+-------+--------+--------+--------+------+
works
+----------+-------+---------+
| courseid | empid | classid |
+----------+-------+---------+
| 1 | 1 | 10 |
| 2 | 2 | 9 |
| 3 | 3 | 8 |
| 4 | 4 | 10 |
| 5 | 5 | 9 |
| 6 | 1 | 9 |
+----------+-------+---------+
The above are the tables from which I need to retrieve the data from.
The question is to return list of Employees who take both Class 10 and
Class 9.
The query I have written is:
select professor.name
from inner join works
on professor.empid=works.empid
where works.classid=9 and works.classid=10;
I know that the result I want is Arun, but I don't know what should be the exact query to retrieve the required result.
He wants the professeors that take class 9 AND 10. So there are 2 different records in works that need to match.
select professor.name from professor
join works A on A.empid=professor.empid and A.classid=9
join works B on B.empid=professor.empid and B.classid=10
See http://sqlfiddle.com/#!2/4be88a/1
Try This
select professor.name
from professor inner join works
on professor.empid=works.empid
where works.classid=9 OR works.classid=10;
(OR)
select professor.name
from professor inner join works
on professor.empid=works.empid
where works.classid IN ('9','10')
SELECT prof.name FROM professor AS prof
JOIN works
ON prof.empid = works.empid
WHERE works.classid IN (9, 10);

How to get all list of data from a table, where it does not appear on another?

I have 5 tables as per below. How is it possible for me to get a list of all training companies that does not have training class data (which means no female or male students), all within a mysql query statement?
select training_companies.*
from training_companies
left join training_centers on training_centers.training_company_id = training_companies.id
left join training_center_programmes on training_centers.id = training_center_programmes.training_center_id
left join training_class_data on training_class_data.training_center_programme_id = training_center_programmes.id
where training_companies.id IS NULL
So far I could only get to here, but I supposed this is wrong. Kindly advise. Thanks.
training_class_data
id | student_category_id | training_centre_programme_id | female | male
1 | 1 | 1 | 10 | 10
2 | 1 | 2 | 10 | 10
3 | 2 | 1 | 10 | 10
4 | 3 | 1 | 10 | 10
training_programmes
id | name
1 | Yoga
2 | Pilates
training_center_programmes
id | training_center_id | status | training_programme_id
1 | 1 | 1 | 1
2 | 2 | 1 | 1
3 | 3 | 1 | 1
4 | 4 | 1 | 2
5 | 5 | 1 | 2
training_centers
id | name | address | postal code | training_company_id
1 | TF Center 1 | abc | 1234 | 1
2 | TF Center 2 | abc | 1234 | 1
3 | TF Center 3 | abc | 1234 | 1
4 | SFT Center 1 | xyz | 2345 | 2
5 | SFT Center 2 | xyz | 2345 | 2
6 | KFT Center 1 | cbd | 4234 | 3
training_companies
id | name | address | postal code
1 | Trim Fitness | abc | 1234
2 | Stay Fit Training | xyz | 2345
3 | Keep Fit Trainers | cbd | 4234
How is it possible for me to get a list of all training companies that
does not have training class data
You just need to use condition d.training_centre_programme_id IS NULL instead of training_companies.id IS NULL:
select DISTINCT c.*
FROM training_companies AS c
LEFT JOIN training_centers AS tc ON tc.training_company_id = c.id
LEFT JOIN training_center_programmes AS p ON p.training_center_id = tc.id
LEFT JOIN training_class_data AS d ON d.training_centre_programme_id = p.id
WHERE d.training_centre_programme_id IS NULL;
SQL Fiddle Demo