How to store schedule time blocks and query against them? - sql

I am using postgres and wondering how I should store schedule time blocks in a way that allows me to do the following:
If I have a schedule with 3 time blocks:
Monday 8am to 12pm
Monday 10am to 4pm
Thursday 8am to 12pm
And I am trying to find all schedules between Monday and Wednesday that start at 8am.
I am storing the time_blocks as array, and I am not sure how to query them.

I suggest three columns:
dow - Day of the week as integer or string. Either would work, integer is best for storage and performance. (0 - 6; Sunday is 0)
from - time type, time of day
to - time type, time of day
Then you can select this way:
SELECT
*
FROM
"schedule"
WHERE
-- Mon, Tue, Wed
"dow" IN (1,2,3) AND
'08:00:00'::time = "from"
You could search for 8am or earlier this way:
'08:00:00'::time BETWEEN "from" AND "to"

Related

GROUP BY different dates for max and min numbers

I am trying to query this data set of hourly price date. The dataset defined daily prices at 12am - 12am UTC time, I am trying to define the days at 4pm - 4pm UTC time. Therefore I need to get the high and the low prices for each day between ex: '2021-12-15 16:00:00' and '2021-12-16 15:00:00' as that would be the open and close of the trading day.
I have this right now:
SELECT convert(date,dateadd(S, TimeStamp/1000, '1970-01-01')) as 'date'
,symbol
,Max([high]) as 'Max'
,Min([low]) as 'Min'
FROM [Crypto].[tblMessariPriceHistory]
WHERE symbol = 'DOGE'
and dateadd(S, TimeStamp/1000, '1970-01-01') between '2021-12-15 16:00:00' and '2021-12-16 15:00:00'
Group By convert(date,dateadd(S, TimeStamp/1000, '1970-01-01')),symbol
But it results like this:
date
symbol
Max
Min
2021-12-15
DOGE
0.175059052503167
0.170510833636204
2021-12-16
DOGE
0.180266282681554
0.177596458601872
I could just group by Symbol but I want to be able to do this over multiple days, and that wouldn't work.
Any ideas on how to define a select date range as a group or table over multiple days?
If you think about it, subtracting 16 h off every time would slide the time back to some time within the "starting day"
Monday 16:00 becomes midnight Monday
Monday 23:59 becomes 7:59 Monday
Tuesday 00:00 becomes 8:00 Monday
Tuesday 15:59 becomes 23:59 Monday
Tuesday 16:00 becomes midnight Tuesday
Anyway, once you've slid your time backwards 16h, you can just chop the time part off by dividing the unix time stamp by the number of milliseconds in a day and all the trades between Monday 16:00 and Tuesday 15:59:59.999 will go down as "Monday". If it were a DateTime we could cast it to a Date to achieve the same thing. It's handy to find ways of treating datetimes as decimal numbers where the integral is the date and the fractional is the time because chopping it to an int discards the time and allows daily aggregating. If you wanted hourly aggregating, adjusting the number so it represents the number of hours and fractions of an hour (divide by 3600000, the number of milliseconds in an hour) helps to the same end
--take off 16h then truncate to number of days since epoch
SELECT
(timestamp-57600000)/86400000 as timestamp,
symbol,
min(low) as minlow,
max(high) as maxhigh
FROM trades
GROUP BY (timestamp-57600000)/86400000 as timestamp, symbol

Represent date/time periods

I'm working on a booking platform which has several different rates. These rates are determined by the time of day, day of week, and day of year. Here are some examples of the interval types involved:
Monday to Friday, 9am to 5pm
Saturday and Sunday, 12am to 9am
Saturday and Sunday, 9am to 5pm
Saturday and Sunday, 5pm to 12am
December 23rd & 24th, anytime
December 26th & 27th, anytime
What is the best way to represent this, such that it's possible to query for the different effective rates on any given day?
At the moment, the way I've done is using two array type columns, days_of_week[] and hours_of_day[], populating them with the days/hours each rate applies. To account for special cases like December, I also have fields valid_from and invalid_after, however this requires a new entry for each year.
I've had a look at the datetime functions for intervals and such here but haven't seen anything that looks like it could solve this.
why not just listing them in where clause? eg for first sample:
t=# select now(),extract('dow' from now()) between 1 and 5 and now()::time between '09:00' and '17:00';
now | ?column?
-------------------------------+----------
2017-11-27 16:56:01.544642+00 | t
so you take (extract('dow' from now()) between 1 and 5 and now()::time between '09:00' and '17:00') to brackets and add same brackets over OR...
You can addthem all to a function with timestamptz as argument and return true of false to use in where clause

Pulling a dynamic day range from the previous year in DB2

I have two current SQL queries that I currently use to compare GM% from previous year vs. GM% this year. This is a daily report that I run every morning. The date arithmetic is not very solid and I am trying to find an alternative. Previously I thought that the report would only be for Monday forward, and not including the current day (ie if ran on Tuesday, it would only pull Monday. If ran on Monday it would not pull anything.) Recently that has changed to where when the report is ran on Monday, they want to see Friday-Sunday. What I am considering is setting it to pull the previous 5 day, not including the current day. (Ran on Monday would pull Thur, Fri, Sat, Sun.) The problem is that it has to be a day this year vs same day last year comparison. Anyone who;s tried this knows that it is not easy to get this. Here is my current code for the date arithmetic. I am at a loss guys, I could use some help.
Where DB1.TB1.CLM1>=Current Date-364 days - (DAYOFWEEK(CURRENT DATE) - 2) DAYS
And DB1.TB1.CLM1< Current Date- 364 days
If I hear you right, on Tuesday you would pull stats for Monday. Wed, you pull stats for Mon-Tues. Friday, you pull Mon-Thurs. And for all of these, you need the equivalent day prior year.
The trick is that now on Monday, you need to pull the previous weekend, i.e. Thu-Sun.
You have not defined what to do on Sunday, so I'm leaving that case out.
Try this WHERE statement:
where
( -- do this after Monday
dayofweek(current date) > 2 and
DB1.TB1.CLM1 between ((current date - 364 days) - (dayofweek(current date) - 2) days) and (current_date - 365 days)
)
or
( -- do this on Monday
dayofweek(current date) = 2 and
DB1.TB1.CLM1 between (current date - 368 days) and (current date - 365 days)
)

Aggregating postgresql rows by date

I have records with values like: date, hour, value. Aggregating whole day is easy, i just group by date. My problem is that i need to aggregate records from whole days with specific start/end time. In example when start time is 9 a.m. then i have records:
- from monday 9 a.m. to tuesday 8 a.m (grouped in one record)
- from tuesday 9 a.m. to wednesday 8 a.m. (grouped in one record)
and so on.
Thanks, for any ideas.
I'm going to assume your hour field is an INT, but regardless you should be able to adapt this...
GROUP BY
CASE WHEN hour >= 9 THEN date ELSE date - 1 END
This essentially treats any hour before 9am as being part of the previous day.
GROUP BY date_trunc('day',date+(hour-9)*interval '1h') or something like that?

SQLite query question

I have 1 table:
table tb1 (
_id integer primary key autoincrement
,busnum text not null
, servdate date not null
);
I need a query which will get me all entries which have a "servdate" for the current week (the week starts on monday.)
So for example:
if I run the query on wednesday the 24th novemeber, it will get me all entries for monday 22nd, tuesday 23rd and wednesday 24th.
If I ran the query on sunday 28th, it will get me all entries for the full week (mon - sun), starting monday 22nd - sunday 28th.
If I run the query on monday, then it will just get me all entries for that day.
Thanks in advance. (thanks to admin for formatting my question)
Use the modifier weekday 1 (from the date time functions documentation) :
WHERE servdate BETWEEN date('now', 'Weekday 1', '-7 days') AND date('now')