I have a Postgres table that looks like this:
Name | Type | Description |
---|---|---|
business_id (PK) | int4 | Business ID |
day (PK) | int4 | Day of week (0-6, monday is zero) |
open | time | Open time |
close | time | Close time |
Every row stores open and closing times for a business on a specific day of week.
Example data for a business looks like this:
business_id | day | open | close |
---|---|---|---|
1 | 0 | 18:00 | 23:00 |
1 | 1 | 18:00 | 23:00 |
1 | 2 | 18:00 | 23:00 |
1 | 3 | 18:00 | 23:00 |
1 | 4 | 18:00 | 01:00 |
1 | 5 | 18:00 | 02:00 |
You can see that the business is opened from 18:00 to 23:00 from Mo.-Fr.
Note that on the weekend the opening hours extend over to the next day.
I’m trying to write a single statement query that determines if a business is opened now or at a specific time.
I tried writing the query below but the results are wrong and I can’t think of another way to solve this problem.
select count(*)
from (
select *
from business_hours bh
where
bh.business_id = 1
and bh.day = extract(dow from now()) - 1
union all
select *
from business_hours bh
where
bh.business_id = 1
and bh.day = extract(dow from now()) - 1
) a
where
("from" < "to" and now()::time between "from" and "to")
or ("from" > "to" and now()::time not between "to" and "from")
Thank you for helping me out with this query
2
Answers
I finally came up with this query and wrapped it inside a function for easier usage:
I'm not 100% sure if this query is correct. My tests showed that it produces the expected result when I called this function with every hour in a week.
Please consider commenting if you think it could be done in a better/more efficient way.
I would use a range type and a constraint to avoid conflicts. Something like this: