简体   繁体   中英

Return the record with the date closest to but greater than now NOW() in table b, for each record in table a

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM