GROUP BY different dates for max and min numbers - sql

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

Related

Google Bigquery, getting beginning and end of the week for a particular time zone

Assuming that the week begins on a Sunday morning (00:00:00) and ends on Saturday night (23:59:59).
Given a particular time zone (ex: 'CST6CDT'), I want to get the corresponding UTC times for beginning and end at this time zone.
Example:
For this week and time zone 'CST6CDT',
Beginning of the week #CST6CDT = 24th November, 00:00:00 corresponds to 24th November, 06:00:00 #UTC
End of the week #CST6CDT = 30th November, 23:59:59 which corresponds to 1st December, 05:59:59 #UTC
I need to get the beginning and end time #UTC as shown above which will be used to extract data. Would really appreciate some help with this.
Below is for BigQuery Standard SQL
#standardSQL
SELECT
TIMESTAMP(DATE_TRUNC(CURRENT_DATE(), WEEK), 'CST6CDT') AS start_week,
TIMESTAMP_SUB(TIMESTAMP(DATE_ADD(DATE_TRUNC(CURRENT_DATE(), WEEK), INTERVAL 1 WEEK), 'CST6CDT'), INTERVAL 1 SECOND) AS end_week
with result
Row start_week end_week
1 2019-11-24 06:00:00 UTC 2019-12-01 05:59:59 UTC
Obviously, you can refactor above for easy reuse as in example below, so you can pass any date of your interest into UDF
#standardSQL
CREATE TEMP FUNCTION week_boundary(day DATE) AS (
STRUCT(
TIMESTAMP(DATE_TRUNC(day, WEEK), 'CST6CDT') AS start_week,
TIMESTAMP_SUB(TIMESTAMP(DATE_ADD(DATE_TRUNC(day, WEEK), INTERVAL 1 WEEK), 'CST6CDT'), INTERVAL 1 SECOND) AS end_week
)
);
SELECT week_boundary(CURRENT_DATE()).*

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

shift out time taking as next date in time in excel

I am a admin of a bio-metric device, there are 3 shifts are going in my office.
In time Out time Date
Shift1 6AM 2PM 5th April
Shift2 2PM 10PM 5th April
Shift3 10PM 5th April 6AM 6th April
but the 3rd shift time intime 10PM is taking as
In time Out Time
day1 out time 10PM
day2 in time 6AM
How can I make it for same date 10PM as intime and 6AM as out time in excel?
And also I want to generate it automatically.
I want the Out Time must shown as the same date.
Date Intime Outtime
5.4.17 6AM 2PM
5.4.17 2PM 10PM
5.4.17 10PM 6AM
And I want to automate the report while generating from web.
=Now() will generate a number (double type) like 42832.8008217593 where the date is shown on the left of the period and the time on the right. 10 PM (22:00:00) will be expressed as 0.9166666667. Add 8 hours to this number (1/24*8) and the result is 1.25 which means, in plain language, "next day 6 AM".
To solve your problem you can use a condition, like, If the end time is on the next day, deduct one day from the result date. This would mean 1.25 - 1 = 0.25 = 6:00AM on the day which is one day earlier than it actually is. Whether your end time is a proper date/time, like 42833.25 or a relative time like 1.25 depends upon how you enter your data.
You can extract the time from the date/time value by calculating (Date/Time - Int(Date/Time), like 1.25 - Int(1.25) = 1.25 -1 = 0.25

Change Character to time stamp in IBM informix DB

I am writing a query to convert a character to Date Time
The following query extracts my time stamps in Character format.
select
(to_char(TO_CHAR(MDY(month(current- 1 units month), 1,year(current- 1 units month)),'%Y-%m-%d')||' 13:00:00')),
(to_char(TO_CHAR((DATE(DATE(extend(TODAY, YEAR TO MONTH)) - 1 UNITS DAY)+1),'%d-%m-%Y')||' 13:00:00'))
from dual
Output:
`T 0÷
2015-08-01 13:00:00 01-09-2015 13:00:00
2015-08-01 13:00:00 01-09-2015 13:00:00
Now I am trying to convert the Character to Time stamp using DATETIME(2001-12-31 15:32:55) YEAR TO SECOND function. I am getting syntax error.
select
DATETIME(to_char(TO_CHAR(MDY(month(current- 1 units month), 1,year(current- 1 units month)),'%Y-%m-%d')||' 13:00:00')) YEAR TO SECOND ,
DATETIME(to_char(TO_CHAR((DATE(DATE(extend(TODAY, YEAR TO MONTH)) - 1 UNITS DAY)+1),'%d-%m-%Y')||' 13:00:00') ) YEAR TO SECOND
from dual
How ever the following is working fine:
select DATETIME(2001-12-31 15:32:55) YEAR TO SECOND
from dual
Thanks in Advance. Please do not suggest answers for Oracle. its damn easy in Oracle.
Try using a CAST to convert your output as a DATETIME YEAR TO SECOND:
select
(to_char(TO_CHAR(MDY(month(current- 1 units month), 1,year(current- 1 units month)),'%Y-%m-%d')||' 13:00:00'))::DATETIME YEAR TO SECOND ,
(to_char(TO_CHAR((DATE(DATE(extend(TODAY, YEAR TO MONTH)) - 1 UNITS DAY)+1),'%Y-%m-%d')||' 13:00:00'))::DATETIME YEAR TO SECOND
from dual
That seems to work OK, but I'd suggest you don't do this. Also, note that DATETIME is an ISO standard: YYYY-MM-DD HH:MM:SS.FFF (or part thereof). Your second example with the date in English format is not going to parse to a DATETIME.
Your first algorithm is not leap-day safe, and the second example is horribly over-complicated. You can determine 13:00 on the first day of the current month using the far simpler construction:
(TODAY-DAY(TODAY)+1)::DATETIME YEAR TO SECOND + INTERVAL(13) HOUR TO HOUR
This also has the benefit of avoiding casting back and forth between DATE and CHAR. The calculation of the same time the previous month can be written as:
MDY(MONTH(TODAY-DAY(TODAY)),1,YEAR(TODAY-DAY(TODAY)))::DATETIME YEAR TO SECOND + INTERVAL(13) HOUR TO HOUR
... which will do the right thing on Feb 29/March 1 in a leap year, which your algorithm won't.
The construction TODAY-DAY(TODAY) will always produce the last day of the prior month.

datetime manipulation: replace all dates with 00:00 time with 24:00 the previous day

I have a table described here: http://sqlfiddle.com/#!3/f8852/3
The date_time field for when the time is 00:00 is wrong. For example:
5/24/2013 00:00
This should really be:
5/23/2013 24:00
So hour 00:00 corresponds to the last hour of the previous day (I didn't create this table but have to work with it). Is there way quick way when I do a select I can replace all dates with 00:00 as the time with 24:00 the previous day? I can do it easily in python in a for loop but not quite sure how to structure it in sql. Appreciate the help.
All datetimes are instants in time, not spans of a finite length, and they can exist in only one day. The instant that represents Midnight is by definition, in the next day, the day in which it is the start of the day, i.e., a day is closed on its beginning and open at its end, or, to phrase it again, valid allowable time values within a single calendar date vary from 00:00:00.00000, to 23:59:59.9999.
This would be analogous to asking that the minute value within an hour be allowed to vary from 1 to 60, instead of from 0 to 59, and that the value of 60 was the last minute of the previous hour.
What you are talking about is only a display issue. Even if you could enter a date as 1 Jan 2013 24:00, (24:00:00 is not a legal time of day) it would be entered as a datetime at the start of the date 2 Jan, not at the end of 1 Jan.
One thing that illustrates this, is to notice that, because of rounding (SQL can only resolve datetimes to within about 300 milleseconds), if you create a datetime that is only a few milleseconds before midnight, it will round up to midnight and move to the next day, as can be seen by running the following in enterprise manager...
Select cast ('1 Jan 2013 23:59:59.999' as datetime)
SQL server stoers all datetimes as two integers, one that represents the number days since 1 Jan 1900, and the other the number of ticks (1 tick is 1/300th of a second, about 3.33 ms), since midnight. If it has been zero time interval since Midnight, it is stll the same day, not the previous day.
If you have been inserting data assuming that midnight 00:00:00 means the end of the day, you need to fix that.
If you need to correct your existing data, you need to add one day to every date in your database that has midnight as it's time component, (i.e., has a zero time component).
Update tbale set
date_time = dateAdd(day, 1, date_time)
Where date_time = dateadd(day, datediff(day, 0, date_time), 0)