Server Version: 10.3.15-MariaDB-log
I have a data structure like this
TABLE A - Participant
participantID
--------------
1
2
3
4
TABLE B - Appointment
appointmentID | participantID | locationID | beginDateTime
----------------------------------------------------------------
1 | 1 | 1 | 2019-10-09 11:00:00
2 | 1 | 1 | 2019-10-10 11:00:00
3 | 2 | 2 | 2019-10-11 11:00:00
4 | 3 | 3 | 2019-11-09 11:00:00
5 | 5 | 1 | 2019-10-15 11:00:00
TABLE C - Location
locationID | locationTypeID
----------------------------
1 | 1
2 | 2
3 | 3
TABLE D - Location Type
locationTypeID | locationType
-----------------------------
1 | mobile
2 | onsite
3 | unknown
I only want to get participants who have an appointment that is in the future, and I only want to return those participants if the location of their future appointment is a mobile location type. However I only care about the location of their nearest future appointment. I need to do this in a single query. I have gotten to this stage, where I am able to get the locationType of all locations, for all appointments greater than now, for all people, but I need to limit this to only their nearest appointment in the future and am not sure how to proceed.
SELECT p.participantID
FROM locationType AS lt
LEFT JOIN location AS l ON l.locationTypeID = lt.locationTypeID
LEFT JOIN appointment AS a ON a.locationID = l.locationID
LEFT JOIN participant AS p ON p.participantID = a.participantID
WHERE p.participantID IN (
SELECT a.participantID
FROM appointment AS a
LEFT JOIN location AS l ON l.locationID = a.locationID
LEFT JOIN locationType AS lt ON lt.locationTypeID = l.locationTYpeID
WHERE a.beginDateTime > NOW()
AND l.locationTypeID IN (
SELECT locationTypeID
FROM locationType
WHERE locationType = 'mobile'
)
);
MariaDB 10.3 supports Window Functions ; so, one way is to simply join the tables based on your requirements, and then calculate row number in ascending order of beginDateTime
. Afterwards, you can use the result as a subquery and consider only those rows where the row number is 1.
ROW_NUMBER() OVER(PARTITION BY p.participantID ORDER BY a.beginDateTime ASC)
: It partitions all the rows together having same p.participantID
value. It is like GROUP BY
, but the main difference here is that GROUP BY
aggregates them into a single row, while PARTITION BY
maintains them as individual rows. Now, within a specific partition of a specific value of p.participantID
, it assigns a row number to individual rows in the ascending order of beginDateTime
value. So, the row with lowest beginDateTime
value gets row number = 1, second lowest as 2, and so on.. Since you want the nearest datetime row, we can then simply consider the row whose row number is 1.
SELECT * FROM
(
SELECT p.participantID,
ROW_NUMBER() OVER(PARTITION BY p.participantID
ORDER BY a.beginDateTime ASC) AS rn
FROM locationType AS lt
JOIN location AS l ON l.locationTypeID = lt.locationTypeID
JOIN appointment AS a ON a.locationID = l.locationID
AND a.beginDateTime > NOW()
JOIN participant AS p ON p.participantID = a.participantID
WHERE lt.locationType = 'Mobile'
) dt
WHERE rn = 1
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.