Reputation: 1259
I have a table with BookingSlots. Each slot is 15 minutes long.
id | startTime | userId | status
-------------------------------------------
1 | 2022-01-01T01:00:00 | 1 | free
-------------------------------------------
2 | 2022-01-01T01:00:00 | 2 | free
-------------------------------------------
3 | 2022-01-01T01:15:00 | 1 | free
-------------------------------------------
4 | 2022-01-01T01:15:00 | 2 | booked
I want to find all BookingSlots that are free at a given date for a timespan of 15 minutes grouped by the userId. So when the I would run the query at 01:08:00
, the result should be:
id | startTime | userId | status
-------------------------------------------
1 | 2022-01-01T01:00:00 | 1 | free
-------------------------------------------
3 | 2022-01-01T01:15:00 | 1 | free
So far my query looks like this:
SELECT
*
FROM
"BookingSlot"
WHERE ("startTime" < '2022-01-01T01:08:00'
AND '2022-01-01T01:08:00' < "startTime" + interval '15 minutes')
OR("startTime" < timestamp '2022-01-01T01:08:00' + interval '15 minutes'
AND timestamp '2022-01-01T01:08:00' + interval '15 minutes' < "startTime" + interval '15 minutes')
AND "status" = 'free'
But the query result includes the row with id 2, which does not match the criteria, because the next slot of user 2 is already booked.
Upvotes: 0
Views: 61
Reputation: 7065
You just have to filter on status = 'free
and startDate
in the right range, and then to select only the userId
with 2 rows filtered using the clause HAVING count(*) = 2
:
SELECT unnest(array_agg(id)) AS id
, unnest(array_agg(startTime)) AS startTime
, userId
, unnest(array_agg(status)) AS status
FROM BookingSlots
WHERE status = 'free'
AND startTime > '2022-01-01T01:08:00' :: timestamp - interval '15 minutes'
AND startTime <= '2022-01-01T01:08:00' :: timestamp + interval '15 minutes'
GROUP BY userId
HAVING count(*) = 2
see dbfiddle
Upvotes: 1