Extracting Hour and Minutes In RedShift Within Same Function - amazon-redshift

I am trying to find rows that came in before 7:30 pm (as part of a CASE WHEN). The below just has it at 8. Any idea how to get this to be 7:30?
extract(dayofweek from convert_timezone('EST', call_start_time)) in (6) and
extract(hour from convert_timezone('EST', call_start_time))
>=8 and extract(hour from convert_timezone('EST', ${TABLE}.call_start_time)) <20

It looks like you want to test if the call_start_time is after 7:30pm EST on ANY day, right?
If so I think you just want to create an interval between the call_start_time and the beginning of that day - call_start_time - date_trunc('day', call_start_time). (Or if you like trunc(timestamp) will give you the date.) Then compare this to the time of day value you want - interval '13 hours 30 minutes'. (13 hours is 19:00 minus 6 hour time zone difference.)
Have I read you question / intent correctly?
====================================
It looks like there is a need to provide a code example. The simplest way to share this is with a sqlfiddle but that means that the syntax will be Postgresql not native Redshift. For the parts of the SQL in question this isn't a change - working with timezones is different but that is handled by an area not in the "interval" calculations.
With prep as (
select *, (t at time zone 'UTC') at time zone 'EST' as est_t,
date_trunc('day', (t at time zone 'UTC') at time zone 'EST') as est_t_date
from fred)
select n, t from prep
where extract(dow from (t at time zone 'UTC') at time zone 'EST') in (6)
and est_t between est_t_date + interval '8 hours'
and est_t_date + interval '19 hours 30 minutes'
;
Live code example at http://sqlfiddle.com/#!17/5236b/2

Related

How can change/convert timezone when I query in PostgreSQL

I need a query to convert timezone in PostgreSQL
I have already tried this query
Select users.last_update_time + interval '7 hours'
And it plus for my result 7 hours.
But I have a problem that if I choose results from 31/01/2022 to 06/02/2022. It will include the result on 07/02/2022. Example before I plus 7 hours, it's on around 17:00 06/02/2022 to 00:00 07/02/2022.
The correct result has to be after +7 hours. So it means that result after plus 7 hours from 17:00 06/02/2022 to 00:00 07/02/2022 shouldn't be in there.
Then you should include the time zone in the query like this:
SELECT ... FROM ...
WHERE tscol BETWEEN '2022-01-31 00:00:00 America/Vancouver'
AND '2022-02-07 00:00:00 America/Vancouver';
If you don't want to hard code the time zone, the best thing is to set the timezone database parameter to the correct time zone in your database session. Then you can use a simple type cast, which will respect the setting:
SELECT ... FROM ...
WHERE tscol BETWEEN CAST ('2022-01-31 00:00:00' AS timestamp with time zone)
AND CAST ('2022-02-07 00:00:00' AS timestamp with time zone);

Postgres query certain overlapping times on weekdays

Imagine you have a set of records for a certain period of time, for example produced products in a month.
Now you want to know how many of those products have been produced at 22 to 3 on Wednesdays and Fridays.
To get all products let's assume the query looks like:
SELECT count(id)
FROM products
WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)
where $startOfMonth and $endOfMonth are placeholder values for some integer timestamps.
To get products of a certain time we can make use of "BETWEEN TIME" and add it to the query:
SELECT count(id)
FROM products
WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)
AND CAST(timestamp AS time) BETWEEN TIME '3:00' AND TIME '22:00'
Next thing we do is adding the exclusive days we want to query:
SELECT count(id)
FROM products
WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)
AND CAST(timestamp AS time) BETWEEN TIME '3:00' AND TIME '22:00'
AND EXTRACT(dow FROM timestamp) IN (3,5)
Everything works fine.
But now I want to query a time overlapping a day:
SELECT count(id)
FROM products
WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)
AND CAST(timestamp AS time) BETWEEN TIME '22:00' AND TIME '12:00'
AND EXTRACT(dow FROM timestamp) IN (3,5)
and I don't receive any results.
How to run this query if the starting time is on another day than the ending time?
Thank you ;-)
BETWEEN TIME '3:00' AND TIME '22:00' seems to be the opposite of what you're asking in the question ("produced at 22 to 3").
I think you'll just have to split the time range and use an OR condition, since it crosses midnight. Assuming that "22 to 3" on a Wednesday, you actually mean "22 to midnight" on a Wednesday and "midnight to 3am" on a Thursday (same for Friday/Saturday)
You won't even need BETWEEN, since the lower/upper bounds will be midnight, when the day changes. Something like this should work:
SELECT count(id)
FROM products
WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)
AND ((CAST(timestamp AS time) >= TIME '22:00'
AND EXTRACT(dow FROM timestamp) IN (3,5))
OR (CAST(timestamp AS time) < TIME '03:00'
AND EXTRACT(dow FROM timestamp) IN (4,6)))
You may need to adapt this a little if you want to include the timestamps that are on the first Thursday or Saturday of the month (before 3am) into the count for the previous month (if it makes sense for your report): a quick way to do this is to adapt the integer timestamp you provide $endOfMonth to be at 3am on the first day of the following month.
(As a side note, I'd avoid using timestamp as a column name, since it's also a type and can cause confusion.)
Perhaps an easier way is to restate the times in question. That is instead of working with TIMEs a 22:00 and 03:00 consider start time as date+22hours and end time as date+27 hours.(duration of 5 hours from 22:00 - 03:00) Then process with the full timestamp.
SELECT count(id)
FROM products
WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)
AND EXTRACT(dow FROM timestamp) IN (3,5)
and timestamp between date_trunc('day', timestamp) + interval '22 hours'
and date_trunc('day', timestamp) + interval '27 hours';
Note: I echo #Bruno on not using timestamp as a column (or any DB object) name. While it is not a Postgres reserved word, Postgres restricts is use and it is a SQL Standard reserved word.

Column of type "timestamp(6) with timezone" and "current time" difference in minutes

I have Oracle 12c DB table and one of it's column utc_timestamp is of type
UTC_TIMESTAMP TIMESTAMP(6) WITH TIME ZONE
It stores timestamp in UTC while current_timestamp and systimestamp both gives timestamp in different timezones.
How can I get time difference in MAX(utc_timestamp) and current_timestamp in minutes ignoring time difference due to different time zones.
For example:
select current_timestamp from dual;
Gives=> 23-AUG-17 04.43.16.253931000 PM AMERICA/CHICAGO
select systimestamp from dual;
Gives=> 23-AUG-17 05.43.16.253925000 PM -04:00
select max(UTC_TIMESTAMP) from table_name;
Gives=> 23-AUG-17 09.40.02.000000000 PM +00:00
For above condition when I run SQL to check time difference between in MAX(utc_timestamp) and current_timestamp I should get number 3.
I think I need something like:
select (extract(minute from current_timestamp) - extract(minute from max(UTC_TIMESTAMP)) * 1440) AS minutesBetween from table_name;
But different timezones are messing it up and I get negative number like -4317. This might be correct as current_timestamp will be higher than max(utc_timestamp) being in CST. So I tried:
select (extract(minute from CAST(current_timestamp as TIMESTAMP(6) WITH TIME ZONE)) - extract(minute from max(UTC_TIMESTAMP)) * 1440) AS minutesBetween from table_name;
This SQL runs without error but producing a big negative number like -83461. Please help me find what am I doing wrong.
You really have two problems here.
One is to convert CURRENT_TIMESTAMP to UTC. That is trivial:
select CURRENT_TIMESTAMP AT TIME ZONE 'UTC' from dual [.....]
(use the AT TIME ZONE clause https://docs.oracle.com/cd/B19306_01/server.102/b14225/ch4datetime.htm#i1007699)
The other is that the difference between two timestamps is an interval, not a number.
select current_timestamp at time zone 'UTC'
- to_timestamp_tz('24-AUG-17 04.00.00.000 AM UTC', 'dd-MON-yy hh.mi.ss.ff AM TZR')
from dual;
produces something like
+00 00:02:39.366000
which means + (positive difference) 00 days, 00 hours, 02 minutes, 39.366 seconds.
If you just want the minutes (always rounded down), you may wrap this whole expression within extract( minute from < ...... > ). Be aware though that the answer will still be 2 (minutes) even if the difference is five hours and two minutes. It is probably best to leave the result in interval data type, unless you are 100% sure (or more) that the result is always less than 1 hour.

Postgresql timestamp and future default values in HSQLDB

I'm working with a legacy postgres db that uses column definitions as follows:
timestamp without time zone default (CURRENT_TIMESTAMP
AT TIME ZONE 'UTC')
and
timestamp without time zone default (CURRENT_TIMESTAMP
AT TIME ZONE 'UTC' + 30 * interval '1 day')
Unfortunately these cannot be changed.
The goal of the latter one is that the default value is 30 days in the future.
I'm trying to add a modern day junit test framework using hsqldb on top of it.
To bring this in line with hsqldb, the first definition needed to be changed to:
timestamp without time zone default CURRENT_TIMESTAMP
AT TIME ZONE INTERVAL '0:00' HOUR TO MINUTE
However, try as I may, I cannot figure out a way to replicate the column with the addition of the 30 days
You can use a TRIGGER for this kind of default value:
CREATE TRIGGER t BEFORE INSERT ON the_table
REFERENCING NEW AS newrow FOR EACH ROW
BEGIN ATOMIC
SET newrow.the_column = CURRENT_TIMESTAMP AT TIME ZONE INTERVAL '0:00' HOUR TO MINUTE + INTERVAL '30' DAY;
END
Update: PostgreSQL compatibility has been extended to accept values in the future. Example
timestamp without time zone default (CURRENT_TIMESTAMP AT TIME ZONE INTERVAL '0:00' HOUR TO MINUTE + INTERVAL 30 DAY))

Select Data over time period

I'm a bit of newbie when it comes to postgres, so bear with me a wee bit and i'll see if i can put up enough information.
i insert weather data into a table every 10 mins, i have a time column that is stamped with an epoch date.
I Have a column of the last hrs rain fall, and every hr that number changes of course with the running total (for that hour).
What i would like to do is skim through the rows to the end of each hour, and get that row, but do it over the last 4 hours, so i would only be returning 4 rows say.
Is this possible in 1 query? Or should i do multiple queries?
I would like to do this in 1 query but not fussed...
Thanks
Thanks guys for your answers, i was/am a bit confused by yours gavin - sorry:) comes from not knowing this terribly well.
I'm still a bit unsure about this, so i'll try and explain it a bit better..
I have a c program that inserts data into the database every 10 mins, it reads the data fom a device that keeps the last hrs rain fall, so every 10 mins it could go up by x amount.
So i guess i have 6 rows / hr of data.
My plan was to go back (in my php page) every 7, which would be the last entry for every hour, and just grab that value. Hence why i would only ever need 4 rows.. just spaced out a bit!
My table (readings) has data like this
index | time (text) | last hrs rain fall (text)
1 | 1316069402 | 1.2
All ears to better ways of storing it too :) I very much appreciate your help too guys thanks.
You should be able to do it in one query...
Would something along the lines of:
SELECT various_columns,
the_hour,
SUM ( column_to_be_summed )
FROM ( SELECT various_columns,
column_to_be_summed,
extract ( hour FROM TIME ) AS the_hour
FROM readings
WHERE TIME > ( NOW() - INTERVAL '4 hour' ) ) a
GROUP BY various_columns,
the_hour ;
do what you need?
SELECT SUM(rainfall) FROM weatherdata WHERE time > (NOW() - INTERVAL '4 hour' );
I don't know column names but that should do it the ones in caps are pgsql types. Is that what you are after?
I am not sure if this is exactly what you are looking for but perhaps it may serve as a basis for adaptation.
I often have a requirment for producing summary data over time periods though I don't use epoch time so there may be better ways of manipulating the values than I have come up with.
create and populate test table
create table epoch_t(etime numeric);
insert into epoch_t
select extract(epoch from generate_series(now(),now() - interval '6 hours',interval '-10 minutes'));
To divide up time into period buckets:
select generate_series(to_char(now(),'yyyy-mm-dd hh24:00:00')::timestamptz,
to_char(now(),'yyyy-mm-dd hh24:00:00')::timestamptz - interval '4 hours',
interval '-1 hour');
Convert epoch time to postgres timestamp:
select timestamptz 'epoch' + etime * '1 second'::interval from epoch_t;
then truncate to hour :
select to_char(timestamptz 'epoch' + etime * '1 second'::interval,
'yyyy-mm-dd hh24:00:00')::timestamptz from epoch_t
To provide summary information by hour :
select to_char(timestamptz 'epoch' + etime * '1 second'::interval,
'yyyy-mm-dd hh24:00:00')::timestamptz,
count(*)
from epoch_t
group by 1
order by 1 desc;
If you might have gaps in the data but need to report zero results use a generate_series to create period buckets and left join to data table.
In this case I create sample hour buckets back prior to the data population above - 9 hours instead of 6 and join on the conversion of epoch time to timestamp truncated to hour.
select per.sample_hour,
sum(case etime is null when true then 0 else 1 end) as etcount
from (select generate_series(to_char(now(),
'yyyy-mm-dd hh24:00:00')::timestamptz,
to_char(now(),'yyyy-mm-dd hh24:00:00')::timestamptz - interval '9 hours',
interval '-1 hour') as sample_hour) as per
left join epoch_t on to_char(timestamptz 'epoch' + etime * '1 second'::interval,
'yyyy-mm-dd hh24:00:00')::timestamptz = per.sample_hour
group by per.sample_hour
order by per.sample_hour desc;