Select data between dates and between times of day - sql

I want to query rows for a given time range and also filter between given times of day.
Example I want to filter for times of day between '9.00 AM' and '10.00 PM' of every date within a given time range.
My table looks like this.
This is my sample code:
SELECT *
FROM public.energy
WHERE time >= date_trunc('month', NOW() - INTERVAL '1 MONTH') AT TIME ZONE 'Asia/Bangkok'
AND time < date_trunc('MINUTE', NOW()- INTERVAL '1 MONTH') AT TIME ZONE 'Asia/Bangkok'
AND name = 'SWU0001'
ORDER BY id DESC;
I already select data between dates that I want, but I want to filter for specific times.

SELECT *
FROM public.energy
WHERE name = 'SWU0001'
AND time >= date_trunc('month' , now() AT TIME ZONE 'Asia/Bangkok' - interval '1 month') AT TIME ZONE 'Asia/Bangkok' -- !
AND time < date_trunc('minute', now() AT TIME ZONE 'Asia/Bangkok' - interval '1 month') AT TIME ZONE 'Asia/Bangkok' -- !
AND (time AT TIME ZONE 'Asia/Bangkok')::time BETWEEN '09:00' AND '22:00' -- !!!
ORDER BY id DESC;
Don't call a timestamptz column "time". The name is misleading, and it's a basic type name.
Also, to work with local time of 'Asia/Bangkok' you need to get the local time for that time zone before applying date_trunc(), and cast the adjusted value back to timestamptz at the end. Basics:
Ignoring time zones altogether in Rails and PostgreSQL

Related

Finding records older than a minute

I have a users table which consists of
some columns like name,age,created_at
created_at contains time in unix timestamps format (epoch).
I basically want to create a query to show all queries that are older than 1 minute.
I tried the following SELECT * FROM users WHERE created_at > NOW() - INTERVAL '1 minutes';
But i got the following error :
operator does not exist: double precesion > timestamp with time zone
Presumably, created_at is actually a Unix timestamp. That means it is measured in seconds, so you can do:
where created_at < extract(epoch from now() - interval '1 minute')

What is the correct syntax for getting timestamps before a certain time?

I would like to return all the timestamps from a database as long as they are before 6 am on the day they were made. I tried to do this:
SELECT source_created_at AT TIME ZONE 'US/PACIFIC' FROM time_entry
WHERE source_created_at AT TIME ZONE 'US/PACIFIC' < '06:00:00'::time
but got this error:
ERROR: operator does not exist: timestamp without time zone < time without time zone
LINE 2: WHERE source_created_at AT TIME ZONE 'US/PACIFIC' < '06:00:0...
I also tried < '06:00:00' and TIME'06:00:00; but got the same error. I'm new to SQL and the documentation has not been helpful here.
You cannot compare a timestamp to a time. You need to cast the timestamp to time first:
WHERE (source_created_at AT TIME ZONE 'US/PACIFIC')::time < '06:00:00'::time
Edit from the comments
If you want all timestamps before tomorrow 6 AM in the same timezone:
WHERE source_created_at at time zone 'US/PACIFIC'
< current_date at time zone 'US/PACIFIC' + interval '1 day 6 hour'

Getting records relative to current date in timezone GMT+8

I wanted to create a report that generate yesterdays records relative to current date in Manila time. Result of the query is wrong until 8AM in Manila time.
I tried subtracting 1 day in current date and convert it in Asia/Manila timezone.
SELECT *
FROM table
WHERE date_field >= current_date at time zone 'Asia/Manila' - interval '1 day'
AND date_field < current_date at time zone 'Asia/Manila'
If today's current date time in manila is 2019-05-25 1AM
My expected result is records from '2019-05-24 00:00:00' - '2019-05-24 23:59:59'
But what I've got is records from '2019-05-23 00:00:00' - '2019-05-23 23:59:59'
Tried running it again at 8AM same date and the result is correct.
This is a little complicated. The current_date is defined at the UTC date. So, when you are calling it, the UTC date is "yesterday", and you are off by one day.
One way to fix this moves the current time into the time zone and then converts to a date:
WHERE date_field >= (current_timestamp at time zone 'Asia/Manila' - interval '1 day')::date AND
date_field < (current_timestamp at time zone 'Asia/Manila')::date

pgSql not pulling all data for a date

The following query against Postgres database some how leaves few rows for the date: 2017-10-01. I have added time zone also. Is there a way to solve this issues?
select min(p.start_timestamp AT TIME ZONE p.timezone AT TIME ZONE 'America/Phoenix') as Date,
'America/Phoenix' AS Timezone, sum(GREATEST(0, p.value)) as Value, p.uom as UnitOfMeasurement
from main.production_ts_2017_10 p
where p.start_timestamp AT TIME ZONE p.timezone >= to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day'
and p.start_timestamp AT TIME ZONE p.timezone <= '2017-10-30'
and p.serial_number = '5T7842974Z'
group by date_trunc('hour', p.start_timestamp AT TIME ZONE p.timezone AT TIME ZONE 'America/Phoenix'), p.uom
order by Date
Let's simplify it down to just this part of the query:
p.start_timestamp AT TIME ZONE p.timezone >= to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day'
This is a conditional expression around the >= operator. It has a left-hand side (p.start_timestamp AT TIME ZONE p.timezone) and a right-hand side: (to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day') that are each evaluated separately, so the final conditional result (true/false) can be determined for each record.
Postgres database some how leaves few rows for the date: 2017-10-01
Look again at the right-hand side of the expression:
to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day'
That reduces down to this value:
'2017-10-02'
In other words, you're limited to records that come after '2017-10-01'. Do you really want that INTERVAL section in there? Did you want to subtract two days instead of add?
Let's assume two things:
You're asking "why does this query show a few rows for October 1st when it should show only rows for October 2nd or later"
p.start_timestamp is of type TIMESTAMP WITHOUT TIME ZONE (I feel safe in assuming this, because otherwise the double-timezone casting of it in other parts of the query makes no sense).
You have this WHERE clause:
where p.start_timestamp AT TIME ZONE p.timezone >= to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day'
Now, the left-hand side of the query is p.start_timestamp AT TIME ZONE p.timezone which will evaluate to a TIMESTAMP WITH TIME ZONE. The right-hand side of the query, however, is to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day' which evaluates to a TIMESTAMP WITHOUT TIMEZONE.
Whenever you compare a TIMESTAMP WITH TIMEZONE to a TIMESTAMP WITHOUT TIMEZONE, the results are going to be dependent on your current TimeZone setting in your psql session, because the TIMESTAMP-no-TZ will be evaluated as if it is in the psql TimeZone. For example, 12:31AM in 'America/Phoenix' on October 2nd can be 11:31AM in 'America/Los_Angeles', depending on the date (and BTW, you chose the worst possible time zone as your default, because America/Phoenix is just wierd). This would result in you seeing records from October 1st, depending on the value of p.timezone.
You're compounding the problem with this:
select min(p.start_timestamp AT TIME ZONE p.timezone AT TIME ZONE 'America/Phoenix') as Date
... so now you're displaying all timestamps as America/Phoenix timestamps regardless of what timezone they were originally in, or what timezone they were compared with. If your TimeZone setting is UTC, you'll see a LOT of October 1st records, because Oct 2nd in UTC overlaps with Oct 1st in America/Phoenix for six or seven hours depending on the date.
I suspect, given the rest of the query, what you want for that WHERE clause is:
where ( p.start_timestamp AT TIME ZONE p.timezone )
>=
( to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day' )
AT TIME ZONE 'America/Phoenix'
AND p.start_timestamp AT TIME ZONE p.timezone
<=
( TIMESTAMP '2017-10-30' AT TIME ZONE 'America/Phoenix' )
All of this is an illustrative lesson in why you should be storing all of your timestamp data as TIMESTAMP WITH TIME ZONE, instead of what you're doing here. As long as you're storing the timezone in a separate field an using AT TIME ZONE all the time, you're going to keep breaking queries. Also, with all of this casting time zones, any indexes you have on those time columns are unlikely to be used.

How to compare dates one with time zone and one without time zone

I have to compare the two dates to get the last 10 min records from database,I'm using postgresql,
I have write this query
select *
FROM x_table
WHERE x_time >= (NOW()::TIMESTAMP WITHOUT TIME ZONE - interval '10 minutes');
x_time is timestamp without time zone so that's why i'm converting the other to the same but it won't giving the result.
Query should written the last 1 min records but i think due to time zone issue it is not giving the result.
how can i resolve the issue?
If x_time is timestamp without time zone, you should specify proper time zone for NOW() function.
Try
select *FROM x_table WHERE x_time >= (NOW() at time zone '-04' - interval '10 minutes')