How to convert interval to timestamp with time zone with postgresql? - postgresql

I want to perform this simple query :
SELECT
pid,
MIN(interval '5 minutes' - current_timestamp - state_change)
FROM
pg_stat_activity
AND
current_timestamp - state_change <= interval '5 minutes'
GROUP BY
pid
ORDER BY
2 ASC
LIMIT 1;
But PG complains that there is no operator between interval and timestamp with time zone.
How can I convert my interval to timestamp ?

The impossible conversion is not the problem, it's a matter of evaluation order. Without changing the order of arguments you may write it with parentheses:
interval '5 minutes' - (current_timestamp - state_change)
and it would work since interval - interval is supported. Without the parentheses it doesn't work since interval - timestamp would be evaluated first and it's not implemented.
As a sidenote, since pid is unique in pg_stat_activity, the GROUP BY pid and MIN should be suppressed, as in:
SELECT
pid,
interval '5 minutes' - (current_timestamp - state_change)
FROM
pg_stat_activity
WHERE
current_timestamp - state_change <= interval '5 minutes'

Related

Why does `date_trunc('day', current_date) + interval '1 day' - interval '1 second'` cause query to hang?

When I set up a date range using max(lasttime) for the upper bound, the query works.
range_values as (
select date_trunc('month', current_date) as minval,
max(lasttime) as maxval
from people
)
When I use date_trunc('day', current_date) + interval '1 day' - interval '1 second' for the upper bound, the query hangs seemingly forever.
range_values as (
select date_trunc('month', current_date) as minval,
(
date_trunc('day', current_date) + interval '1 day' - interval '1 second'
) as maxval
from people
)
Here's how those values differ.
select max(lasttime) as max_lasttime, (date_trunc('day', current_date) + interval '1 day' - interval '1 second') as end_of_day from people;
{
"max_lasttime": "2023-02-13 07:30:01",
"end_of_day": "2023-02-13 23:59:59-07"
}
I expected this would not make a difference. Why does it?
PostgreSQL 10.18 (Ubuntu 10.18-0ubuntu0.18.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0, 64-bit
In the 1st query, you are using an aggregate (max) so the output is a single row, regardless of the size of the people table.
In the 2nd query, you are fetching 2 constant values for every row in the people, so chances are you are building a massive cross-join with another (or the same!) table.

current_date in redshift exclude today's date when i am using with between command

I want to query data for last 30 days including today from redshift table. below is my query.
my date_column's type is 'timestamp without timezone'
select *
from mytable
WHERE date_column BETWEEN current_date - INTERVAL '30 day' AND current_date
order by date_column desc;
It gives the result for 30 days. But it doesn't include today's result.
I want to query for 30 days result including today's result also.
If it's a timestamp don't use between as it also compares the time part. Use a range query:
where date_column >= current_date - interval '30 day'
and date_column < current_date + interval '1 day'
Note that the upper bound is using < together with "tomorrow"
With Postgres this could be simplified to
where date_column >= current_date - 30
and date_column < current_date + 1
but Redshift isn't Postgres and I don't know if that would work there.

Postgresql - query to get difference in data count

I have two tables, today's_table and yeterday's_table.
I need to compare the data for an interval of 15 mins at exact same times for today and yesterday.
For example, for below data let's I need to check from 00:00:00 and 00:15:00 on 20201202 and 20201202. So difference should come out as '3' since the yesterday's_table has 8 records and today's_table has 5 records.
today's_table:
Yesterday's table:
I tried something like; (consider now() is 00:15:00)
select count(*) from yeterday's_table where time between now() - interval "24 hours" and now() - interval "23 hours 45 mins"
minus
select count(*) from today's_table where time = now() - interval "15 minutes";
is there any other way to do this?
You can easily do this with subqueries:
SELECT b.c - a.c
FROM (select count(*) as c from yeterdays_table where time between now() - interval '24 hours' and now() - interval '23 hours 45 mins') a,
(select count(*) as c from todays_table where time = now() - interval '15 minutes') b;
Bear in mind you need to single-quote your intervals, and your table names cannot have quotes in them.

PostgreSQL - Difference between Current Date and a Date from Database

I'm trying to make a SELECT query which will compare current time with time at database. For example in database there is a record '2018-02-07 12:00:00' and I wanna compare it to current time. If current time is '2018-02-07 11:00:00', record '2018-02-07 12:00:00' should be visible in results. It should compare two dates and shows only those who are 1h before or after current time.'
Tried something like this:
SELECT * FROM events WHERE age(current_date, event_date) < '1 hour';
or
SELECT * FROM events WHERE event_date > (now() - INTERVAL '1 hour');
those that are 1h before or after current time
Wouldn't the logic look like this?
SELECT e.*
FROM events e
WHERE e.event_date > now() - INTERVAL '1 hour' AND
e.event_date < now() + INTERVAL '1 hour'

Update time only if not a minute passed

I have created the next table.
-- TABLE user_time
user_id integer PRIMARY KEY,
prev_time TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW(),
total_time INTERVAL DEFAULT interval '0 second'
I have to add an interval value to the total_time, e.g.
total_time = total_time + NOW() - prev_time
only if not a minute passed since prev_time (so, less than 1 minute passed) in a single query.
The next construction is about what I want but it's wrong:
UPDATE user_time SET total_time = total_time +
(
SELECT NOW() - prev_time incinterval,
CASE
WHEN incinterval < interval '1 minute' THEN incinterval
ELSE interval '0 second'
END
FROM user_time WHERE user_id=6
)
Firstly the SELECT is wrong, PostgreSQL does not recognize incinterval in the CASE construction. Secondly there is the first extra column in SELECT which creates a pseudo name.
Do you have an idea how to correct the query OR
Is it the common practice to increment total time with the condition and store it to a database with a single query?
You can not expect Postgres to respect your alias like this inside a SELECT. Here's the way to go:
UPDATE user_time SET total_time = total_time +
(
SELECT
CASE
WHEN NOW() - prev_time < interval '1 minute'
THEN NOW() - prev_time
ELSE interval '0 second'
END
FROM user_time WHERE user_id=6
)
Or to use your alias:
UPDATE user_time SET total_time = total_time +
(
SELECT
CASE
WHEN incinterval < interval '1 minute'
THEN incinterval
ELSE interval '0 second'
END
FROM(
SELECT
NOW() - prev_time incinterval
FROM user_time WHERE user_id=6
) foo
)
Edit after comment:
Simply add , prev_time = NOW() after the last parenthesis in any option you choose from those above.
The deadlock issue can be resolved by doing the analysis post hoc. Just log the queries and "roll up" clusters that meet your interval spec. This allows for variable-length intervals, which can be very useful for sites that provide dense content.
The "post hoc" process can/should run periodically in overlapping ranges to catch longer intervals.
There is an relevant example of a generalizable temporal clustering query using analytic functions from about 8 years ago on asktom.oracle.com.