The Problem:
Construct the SQL statement to find the number of attendees for every meeting. Display the following columns:
Count of meeting attendees
Meeting ID
Meeting start date and time
Meeting end date and time
There are 5 tables in this database(person, building, room, meeting, person_meeting
+-----------+------------+------------+
| person_id | first_name | last_name |
+-----------+------------+------------+
| 1 | Tom | Hanks |
| 2 | Anne | Hathaway |
| 3 | Tom | Cruise |
| 4 | Meryl | Streep |
| 5 | Chris | Pratt |
| 6 | Halle | Berry |
| 7 | Robert | De Niro |
| 8 | Julia | Roberts |
| 9 | Denzel | Washington |
| 10 | Melissa | McCarthy |
+-----------+------------+------------+
+-------------+----------------------+
| building_id | building_name |
+-------------+----------------------+
| 1 | Headquarters |
| 2 | Main Street Buidling |
+-------------+----------------------+
+---------+-------------+-------------+----------+
| room_id | room_number | building_id | capacity |
+---------+-------------+-------------+----------+
| 1 | 100 | 1 | 5 |
| 2 | 200 | 1 | 4 |
| 3 | 300 | 1 | 10 |
| 4 | 10 | 2 | 4 |
| 5 | 20 | 2 | 4 |
+---------+-------------+-------------+----------+
+------------+---------+---------------------+---------------------+
| meeting_id | room_id | meeting_start | meeting_end |
+------------+---------+---------------------+---------------------+
| 1 | 1 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
| 2 | 1 | 2016-12-25 10:00:00 | 2016-12-25 12:00:00 |
| 3 | 1 | 2016-12-25 11:00:00 | 2016-12-25 12:00:00 |
| 4 | 2 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
| 5 | 4 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
| 6 | 5 | 2016-12-25 14:00:00 | 2016-12-25 16:00:00 |
+------------+---------+---------------------+---------------------+
+-----------+------------+
| person_id | meeting_id |
+-----------+------------+
| 1 | 1 |
| 10 | 1 |
| 1 | 2 |
| 2 | 2 |
| 3 | 2 |
| 4 | 2 |
| 5 | 2 |
| 6 | 2 |
| 7 | 2 |
| 8 | 2 |
| 9 | 3 |
| 10 | 3 |
| 1 | 4 |
| 2 | 4 |
| 8 | 5 |
| 9 | 5 |
| 1 | 6 |
| 2 | 6 |
| 3 | 6 |
+-----------+------------+
My SQL statement:
SELECT Count(person_id) AS “Count of meeting attendees” ,meeting_id,meeting_start,meeting_end
FROM meeting M ,person_meeting PM
WHERE M. meeting_id=PM. meeting_id
Group by PM.meeting_id,M.meeting_start,M.meeting_end;
The error I get:
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'of meeting attendees” ,meeting_id,meeting_start,meet
ing_end
FROM meeting M ' at line 1
Please Help me, I am not sure What I am doing wrong. I have not been able to find a solution for this problem
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
Don't give you columns aliases that need to be escaped. So, use underscores rather than spaces. This fixes your problem with the weird double quote characters:
SELECT COUNT(pm.person_id) AS num_attendees,
m.meeting_id, m.meeting_start, m.meeting_end
FROM meeting m JOIN
person_meeting PM
ON m.meeting_id = pm.meeting_id
GROUP BY m.meeting_id, m.meeting_start, m.meeting_end ;
Based on the error text I would try changing the name of your COUNT() column to just 'Count', since the error message starts just after the first space in your column name
EDIT:
I will also second Gordon Linoff's statement:
never do this:
FROM tbla a, tblb b
WHERE a.columna = b.columnb
That's a regular old join, and it should be written as such:
FROM tbla A
JOIN tblb B ON a.columna = b.columnb
There are 2 things that can be changed. First meeting_id column belongs to both table so you have to define which table's column. And then the column naming must have error depending on error description you have provided.
SELECT Count(person_id) AS "Count" ,M.meeting_id,meeting_start,meeting_end
FROM meeting M
INNER JOIN person_meeting PM ON M.meeting_id=PM.meeting_id
Group by M.meeting_id,M.meeting_start,M.meeting_end;
Related
I have 4 tables: the first is the client table, which has customer info, and client_id as an auto-increment primary key.
The second and third are identical in structure: they are used to track attendance to 2 different therapy programs. They each have a primary key, and a client_id column to track the client. One of the fields contains units, which I want to sum.
The last table contains the therapists' info.
Basically I want to extract total amount of units for each client from the two attendance tables.
I have tried LEFT JOINS to no avail. I also tried a UNION ALL, but couldn't get it to sum the units.
This is how the tables look:
client:
+---------------------------------------+
| client_id | f_name | l_name | th_id |
|-----------|----------|--------|-------|
| 1 | sherlock | holmes | 1 |
| 2 | john | watson | 4 |
| 3 | hercule | poirot | 3 |
| 4 | jane | marple | 2 |
+---------------------------------------+
therapist:
+--------------------------+
| th_id | f_name | l_name |
|-------|---------|--------|
| 1 | james | kirk |
| 2 | mr | spock |
| 3 | bones | mccoy |
| 4 | nyota | uhura |
+--------------------------+
attendance it:
+-------------------------------+
| it_id | client_id | units |
|-----------|-----------|-------|
| 1 | 1 | 4 |
| 2 | 1 | 4 |
| 3 | 1 | 0 |
| 4 | 1 | 2 |
| 5 | 4 | 0 |
| 6 | 4 | 4 |
| 7 | 4 | 0 |
| 8 | 4 | 2 |
+-------------------------------+
attendance psr:
+-------------------------------+
| it_id | client_id | units |
|-----------|-----------|-------|
| 1 | 1 | 16 |
| 2 | 1 | 16 |
| 3 | 1 | 0 |
| 4 | 1 | 12 |
| 5 | 4 | 0 |
| 6 | 4 | 14 |
| 7 | 4 | 8 |
| 8 | 4 | 10 |
+-------------------------------+
The result should look like this:
+------------------------------------------------------------+
| client_id | total_units_it | total_units_psr | therapist |
|-----------|----------------|-----------------|-------------|
| 1 | 10 | 44 | james kirk |
| 4 | 6 | 32 | mr spock |
+------------------------------------------------------------+
Please excuse the primitive representations, and please don't ask why the tables are designed like that... ;-) Also, I obviously ignored many other fields which are not relevant to the question, such as dates, etc.
Any advice would be appreciated.
Thanks!
You can't use join or you will create Cartesian product and duplicate the rows.
Instead you do a subquery:
SELECT c.*
, (SELECT SUM(units) FROM attendance_it a WHERE a.client_id = c.client_id ) as total_units_it
, (SELECT SUM(units) FROM attendance psr a WHERE a.client_id = c.client_id ) as total_units_psr
, t.*
FROM client c
JOIN therapist t
ON c.th_id = t.th_id
use group by client_id to get the sum of each client. and no need to use join as you have already the ids in column.
Hey Guys I need Help with an SQL statement. There are 5 tables total and I need to join multiple tables for a SELECT statement.
These are the tables:
+-----------+------------+------------+
| person_id | first_name | last_name |
+-----------+------------+------------+
| 1 | Tom | Hanks |
| 2 | Anne | Hathaway |
| 3 | Tom | Cruise |
| 4 | Meryl | Streep |
| 5 | Chris | Pratt |
| 6 | Halle | Berry |
| 7 | Robert | De Niro |
| 8 | Julia | Roberts |
| 9 | Denzel | Washington |
| 10 | Melissa | McCarthy |
+-----------+------------+------------+
+-------------+----------------------+
| building_id | building_name |
+-------------+----------------------+
| 1 | Headquarters |
| 2 | Main Street Building |
+-------------+----------------------+
+---------+-------------+-------------+----------+
| room_id | room_number | building_id | capacity |
+---------+-------------+-------------+----------+
| 1 | 100 | 1 | 5 |
| 2 | 200 | 1 | 4 |
| 3 | 300 | 1 | 10 |
| 4 | 10 | 2 | 4 |
| 5 | 20 | 2 | 4 |
+---------+-------------+-------------+----------+
+------------+---------+---------------------+---------------------+
| meeting_id | room_id | meeting_start | meeting_end |
+------------+---------+---------------------+---------------------+
| 1 | 1 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
| 2 | 1 | 2016-12-25 10:00:00 | 2016-12-25 12:00:00 |
| 3 | 1 | 2016-12-25 11:00:00 | 2016-12-25 12:00:00 |
| 4 | 2 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
| 5 | 4 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
| 6 | 5 | 2016-12-25 14:00:00 | 2016-12-25 16:00:00 |
+------------+---------+---------------------+---------------------+
+-----------+------------+
| person_id | meeting_id |
+-----------+------------+
| 1 | 1 |
| 10 | 1 |
| 1 | 2 |
| 2 | 2 |
| 3 | 2 |
| 4 | 2 |
| 5 | 2 |
| 6 | 2 |
| 7 | 2 |
| 8 | 2 |
| 9 | 3 |
| 10 | 3 |
| 1 | 4 |
| 2 | 4 |
| 8 | 5 |
| 9 | 5 |
| 1 | 6 |
| 2 | 6 |
| 3 | 6 |
+-----------+------------+
The problem:
Construct the SQL statement to find all the meetings that Tom Hanks has to attend. Display the following columns:
Person’s first name
Person’s last name
Building name
Room number
Meeting start date and time
Meeting end date and time
My statement:
SELECT person.first_name, person.last_name, building.building_name,
->
-> room.room_number, meeting.meeting_start, meeting.meeting_end
->
-> FROM person
->
-> JOIN building
->
-> ON person.person_id = building.building_id
->
-> JOIN room
->
-> ON person.person_id = room.room_id
->
-> JOIN meeting
->
-> ON person.person_id = meeting.meeting_id
->
-> WHERE person_id = 1;
RESULT:
+------------+-----------+---------------+-------------+---------------------+---------------------+
| first_name | last_name | building_name | room_number | meeting_start | meeting_end |
+------------+-----------+---------------+-------------+---------------------+---------------------+
| Tom | Hanks | Headquarters | 100 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
+------------+-----------+---------------+-------------+---------------------+---------------------+
Tom Hanks has multiple meetings.(4 to be exact) How do I show the 4 meetings? Not sure what to do here. It is only showing 1 with my statement.
Was able to find a solution. JOIN was not needed...
SELECT first_name,last_name ,building_name,room_number ,meeting_start,meeting_end
FROM person P, building B,person_meeting PM,meeting M,room R
WHERE
P.person_id=PM.person_id
AND M.room_id=R.room_id
AND B.building_id=R.building_id
AND PM.meeting_id=M.meeting_id
AND P.first_name='Tom'
AND P.last_name='Hanks';
This query should give you what you want (barring any spelling mistakes :P!)
SELECT person.first_name,
person.last_name,
building.building_name,
room.room_number,
meeting.meeting_start,
meeting.meeting_end
FROM person
INNER JOIN person_meeting ON person_meeting.person_id = person.person_id
INNER JOIN meeting ON meeting.meeting_id = person_meeting.meeting_id
INNER JOIN room ON room.room_id = meeting.room_id
INNER JOIN building on building.building_id = room.building_id
WHERE person.person_id = 1
With this query you are joining the tables on the relationships you've created.
A person is linked to meeting via meeting.person_id = person.person_id a meeting is linked to a room via room.room_id = meeting.room_id and a room is linked to a building via building.building_id = room.room_id then finally filtering down these to only show where person.person_id = 1
The issue with your query was you tried to join everything onto person via person_id
JOIN building ON person.person_id = building.building_id
+-------------+----------------------+
| building_id | building_name |
+-------------+----------------------+
| 1 | Headquarters |<-
| 2 | Main Street Building |
+-------------+----------------------+
from this table we will only get building_id = 1
JOIN room ON person.person_id = room.room_id
+---------+-------------+-------------+----------+
| room_id | room_number | building_id | capacity |
+---------+-------------+-------------+----------+
| 1 | 100 | 1 | 5 | <-
| 2 | 200 | 1 | 4 |
| 3 | 300 | 1 | 10 |
| 4 | 10 | 2 | 4 |
| 5 | 20 | 2 | 4 |
+---------+-------------+-------------+----------+
from this table we will only get room_id = 1
JOIN meeting ON person.person_id = meeting.meeting_id
+------------+---------+---------------------+---------------------+
| meeting_id | room_id | meeting_start | meeting_end |
+------------+---------+---------------------+---------------------+
| 1 | 1 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 | <-
| 2 | 1 | 2016-12-25 10:00:00 | 2016-12-25 12:00:00 |
| 3 | 1 | 2016-12-25 11:00:00 | 2016-12-25 12:00:00 |
| 4 | 2 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
| 5 | 4 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
| 6 | 5 | 2016-12-25 14:00:00 | 2016-12-25 16:00:00 |
+------------+---------+---------------------+---------------------+
from this table we can see we will only get meeting_id = 1
Primary Keys/Foreign Keys
Person.person_id is your PK and meeting.person_id is your FK
room.room_id is your PK and meeting.room_id is your FK
Building.building_id is your PK and room.building_id is your FK
SQL Fiddle
The Problem:
Construct the SQL statement to find all of the people that have meetings only before Dec. 25, 2016 at noon using INNER JOINs. Display the following columns:
Person’s first name
Person’s last name
Meeting ID
Meeting start date and time
Meeting end date and time
The Tables:
There are 5 tables in this database(person, building, room, meeting, person_meeting
+-----------+------------+------------+
| person_id | first_name | last_name |
+-----------+------------+------------+
| 1 | Tom | Hanks |
| 2 | Anne | Hathaway |
| 3 | Tom | Cruise |
| 4 | Meryl | Streep |
| 5 | Chris | Pratt |
| 6 | Halle | Berry |
| 7 | Robert | De Niro |
| 8 | Julia | Roberts |
| 9 | Denzel | Washington |
| 10 | Melissa | McCarthy |
+-----------+------------+------------+
+-------------+----------------------+
| building_id | building_name |
+-------------+----------------------+
| 1 | Headquarters |
| 2 | Main Street Buidling |
+-------------+----------------------+
+---------+-------------+-------------+----------+
| room_id | room_number | building_id | capacity |
+---------+-------------+-------------+----------+
| 1 | 100 | 1 | 5 |
| 2 | 200 | 1 | 4 |
| 3 | 300 | 1 | 10 |
| 4 | 10 | 2 | 4 |
| 5 | 20 | 2 | 4 |
+---------+-------------+-------------+----------+
+------------+---------+---------------------+---------------------+
| meeting_id | room_id | meeting_start | meeting_end |
+------------+---------+---------------------+---------------------+
| 1 | 1 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
| 2 | 1 | 2016-12-25 10:00:00 | 2016-12-25 12:00:00 |
| 3 | 1 | 2016-12-25 11:00:00 | 2016-12-25 12:00:00 |
| 4 | 2 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
| 5 | 4 | 2016-12-25 09:00:00 | 2016-12-25 10:00:00 |
| 6 | 5 | 2016-12-25 14:00:00 | 2016-12-25 16:00:00 |
+------------+---------+---------------------+---------------------+
+-----------+------------+
| person_id | meeting_id |
+-----------+------------+
| 1 | 1 |
| 10 | 1 |
| 1 | 2 |
| 2 | 2 |
| 3 | 2 |
| 4 | 2 |
| 5 | 2 |
| 6 | 2 |
| 7 | 2 |
| 8 | 2 |
| 9 | 3 |
| 10 | 3 |
| 1 | 4 |
| 2 | 4 |
| 8 | 5 |
| 9 | 5 |
| 1 | 6 |
| 2 | 6 |
| 3 | 6 |
+-----------+------------+
My Solution so Far:
SELECT first_name,last_name ,building_name,meeting_start,meeting_end
FROM person P
INNER JOIN building B
ON P.person_id=PM.person_id
INNER JOIN person_meeting PM
ON M.room_id
I'm having trouble completing the SQL statement, please help if possible.
this might do the trick for you. I used aliases for each of the tables in the join and used them in the select statements for the columns you needed. Then I joined the needed tables and in the where it determines the ones with a meeting_end before dec 12 at noon. (i assume, if you wanted it start just switch it to meeting_start)
select p.first_name,p.last_name,pm.meeting_id,m.meeting_start,m.meeting_end from person p
inner join person_meeting pm on pm.person_id = p.person_id
inner join meeting m on m.meeting_id = pm.meeting_id
where m.meeting_end > '2016-12-25 12:00:00'
I have the following structure :
Table Author :
idAuthor,
Name
+----------+-------+
| idAuthor | Name |
+----------+-------+
| 1 | Renee |
| 2 | John |
| 3 | Bob |
| 4 | Bryan |
+----------+-------+
Table Publication:
idPublication,
Title,
Type,
Date,
Journal,
Conference
+---------------+--------------+------+-------------+------------+-----------+
| idPublication | Title | Date | Type | Conference | Journal |
+---------------+--------------+------+-------------+------------+-----------+
| 1 | Flower thing | 2008 | book | NULL | NULL |
| 2 | Bees | 2009 | article | NULL | Le Monde |
| 3 | Wasps | 2010 | inproceding | KDD | NULL |
| 4 | Whales | 2010 | inproceding | DPC | NULL |
| 5 | Lyon | 2011 | article | NULL | Le Figaro |
| 6 | Plants | 2012 | book | NULL | NULL |
| 7 | Walls | 2009 | proceeding | KDD | NULL |
| 8 | Juices | 2010 | proceeding | KDD | NULL |
| 9 | Fruits | 2010 | proceeding | DPC | NULL |
| 10 | Computers | 2010 | inproceding | DPC | NULL |
| 11 | Phones | 2010 | inproceding | DPC | NULL |
| 12 | Creams | 2010 | proceeding | DPC | NULL |
| 13 | Love | 2010 | proceeding | DPC | NULL |
+---------------+--------------+------+-------------+------------+-----------+
Table author_has_publication :
Author_idAuthor,
Publication_idPublication
+-----------------+---------------------------+
| Author_idAuthor | Publication_idPublication |
+-----------------+---------------------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 1 | 5 |
| 2 | 5 |
| 3 | 5 |
| 3 | 6 |
| 4 | 7 |
| 4 | 8 |
| 4 | 9 |
| 4 | 10 |
| 3 | 11 |
| 3 | 12 |
| 2 | 13 |
+-----------------+---------------------------+
I want to obtain the list of all authors having published at least 2 times at conference DPC in 2010.
I achieved to get the list of autors that have published something, and the number of publication for each, but I can't get my 'at least 2' factor.
My following query
SELECT author.name, COUNT(name) FROM author INNER JOIN author_has_publication ON author.idAuthor=author_has_publication.Author_idAuthor INNER JOIN publication ON author_has_publication.Publication_idPublication=publication.idPublication AND publication.date=2010 AND publication.conference='DPC'GROUP BY author.name;
returns the following result (which is good)
+-------+-------------+
| name | COUNT(name) |
+-------+-------------+
| Bob | 2 |
| Bryan | 3 |
| John | 1 |
+-------+-------------+
but when I try to select only the one with a count(name)>=2, i got an error.
I tried this query :
SELECT author.name, COUNT(name) FROM author INNER JOIN author_has_publication ON author.idAuthor=author_has_publication.Author_idAuthor INNER JOIN publication ON author_has_publication.Publication_idPublication=publication.idPublication AND publication.date=2010 AND publication.conference='DPC'GROUP BY author.name WHERE COUNT(name)>=2;
When you use aggregation funcion you can filter with a proper operator named HAVING
Having worok on the result of the query (then pn the aggrgated result like count() ) instead of where that work on the original value of the tables rows
SELECT author.name, COUNT(name)
FROM author INNER JOIN author_has_publication
ON author.idAuthor=author_has_publication.Author_idAuthor
INNER JOIN publication
ON author_has_publication.Publication_idPublication=publication.idPublication
AND publication.date=2010 AND publication.conference='DPC'
GROUP BY author.name
HAVING COUNT(name)>=2;
I'm new here, someone would have a possible solution to a problem I could not solve with subquery, any idea how to solve the problem?
Basically I need all patients "pa_name", most current exam for each "field: pe_d2" Like "Expected Result:"
I tried to make a sketch of the result, might help understand the problem ...
The "pacient_exams" table has very many records, the query needs to be very fast.
Thanks in advance for possible solutions! []
patient_exams
+-------+----------+----------+------------+------------+
| pe_id | pe_pa_id | pe_ex_id | pe_d1 | pe_d2 |
+-------+----------+----------+------------+------------+
| 1 | 1 | 1 | 2014-05-19 | 2016-05-19 |
| 2 | 1 | 2 | 2014-05-19 | 2015-05-19 |
| 3 | 1 | 3 | 2014-05-26 | 2014-11-26 |
| 4 | 1 | 3 | 2014-05-19 | 2014-11-19 |
| 5 | 1 | 4 | 2013-05-19 | 2013-11-19 |
| 6 | 1 | 4 | 2014-05-19 | 2014-11-19 |
| 7 | 3 | 1 | 2013-08-19 | 2014-08-19 |
| 8 | 3 | 1 | 2014-05-01 | 2017-05-01 |
| 9 | 4 | 2 | 2013-05-02 | 2014-05-02 |
| 10 | 4 | 2 | 2013-11-01 | 2014-05-01 |
| 11 | 4 | 4 | 2013-05-02 | 2014-05-02 |
| 12 | 4 | 4 | 2013-11-01 | 2014-05-01 |
+-------+----------+----------+------------+------------+
patient exams
+-------+---------+ +-------+---------+
| pa_id | pa_name | | ex_id | ex_name |
+-------+---------+ +-------+---------+
| 1 | John M. | | 1 | Exam 1 |
| 2 | Slater | | 2 | Exam 2 |
| 3 | Jonny | | 3 | Exam 3 |
| 4 | Jessy | | 4 | Exam 4 |
| ... | ... | | ... | ... |
+-------+---------+ +-------+---------+
Expected Result:
+-------+---------+---------+------------+------------+
| pe_id | pa_name | ex_name | pe_d1 | pe_d2 |
+-------+---------+---------+------------+------------+
| 9 | Jessy | Exam 2 | 2013-05-02 | 2014-05-02 |
| 11 | Jessy | Exam 4 | 2013-05-02 | 2014-05-02 |
| 1 | John M. | Exam 1 | 2014-05-19 | 2016-05-19 |
| 2 | John M. | Exam 2 | 2014-05-19 | 2015-05-19 |
| 3 | John M. | Exam 3 | 2014-05-26 | 2014-11-26 |
| 6 | John M. | Exam 4 | 2014-05-26 | 2014-11-26 |
| 8 | Jonny | Exam 1 | 2014-05-01 | 2017-05-01 |
+-------+---------+---------+------------+------------+
You need to first get the latest records from the patient_exams table and then join all the 3 tables with the filtered results, like this:
SELECT pe_id, pa_name, ex_name, pe_d1, pe_d2
FROM patient_exams pe
JOIN patient p
ON pe.pe_pa_id = p.pa_id
JOIN exams e
ON pe.pe_ex_id = e.ex_id
JOIN (
SELECT pe_pa_id, pe_ex_id, MAX(pe_d2) AS max_pe_d2
FROM patient_exams
GROUP BY pe_pa_id, pe_ex_id
) AS t
ON pe.pe_pa_id = t.pe_pa_id
AND pe.pe_ex_id = t.pe_ex_id
AND pe.pe_d2 = t.max_pe_d2
ORDER BY pa_name, ex_name
Demo/Solution
Thanks to everyone, works fine!
You can use joins among your tables,for the max exam date you need an additional self join to patient_exams with a subquery to get the maxima of exam date i.e max(pe_d2)
select
pe.pe_id,
p.pa_name ,
e.ex_name ,
pe.pe_d1 ,
pe.pe_d2
from exams e
join patient_exams pe on(e.ex_id = pe.pe_ex_id)
join patient p on(p.pa_id= pe.pe_pa_id)
join (select `pe_pa_id`, `pe_ex_id` ,max(pe_d2) pe_d2
from patient_exams
group by `pe_pa_id`, `pe_ex_id`) pee
on (pe.`pe_pa_id`= pee.`pe_pa_id` and
pe.`pe_ex_id` = pee.`pe_ex_id` and
pe.pe_d2 = pee.pe_d2
)
order by p.pa_name ,pee.pe_d2 desc
Demo