Select today's (since midnight) timestamps only - postgresql

I have a server with PostgreSQL 8.4 which is being rebooted every night at 01:00 (don't ask) and need to get a list of connected users (i.e. their timestamps are u.login > u.logout):
SELECT u.login, u.id, u.first_name
FROM pref_users u
WHERE u.login > u.logout and
u.login > now() - interval '24 hour'
ORDER BY u.login;
login | id | first_name
----------------------------+----------------+-------------
2012-03-14 09:27:33.41645 | OK171511218029 | Alice
2012-03-14 09:51:46.387244 | OK448670789462 | Bob
2012-03-14 09:52:36.738625 | OK5088512947 | Sergej
But comparing u.login > now()-interval '24 hour' also delivers the users before the last 01:00, which is bad, esp. in the mornings.
Is there any efficient way to get the logins since the last 01:00 without doing string acrobatics with to_char()?

This should be 1) correct and 2) as fast as possible:
SELECT u.login, u.id, u.first_name
FROM pref_users u
WHERE u.login >= now()::date + interval '1h'
AND u.login > u.logout
ORDER BY u.login;
As there are no future timestamps in your table (I assume), you need no upper bound.
Some equivalent expressions:
SELECT localtimestamp::date + interval '1h'
, current_date + interval '1h'
, date_trunc('day', now()) + interval '1h'
, now()::date + interval '1h'
now()::date used to perform slightly faster than CURRENT_DATE in older versions, but that's not true any more in modern Postgres. But either is still faster than LOCALTIMESTAMP in Postgres 14 for some reason.
date_trunc('day', now()) + interval '1h' slightly differs in that it returns timestamptz. But it is coerced to timestamp according to the timezone setting of the current session in comparison to the timestamp column login, doing effectively the same.
See:
Ignoring time zones altogether in Rails and PostgreSQL
To return rows for the previous day instead of returning nothing when issued between 00:00 and 01:00 local time, use instead:
WHERE u.login >= (LOCALTIMESTAMP - interval '1h')::date + interval '1h'

select * from termin where DATE(dateTimeField) >= CURRENT_DATE AND DATE(dateTimeField) < CURRENT_DATE + INTERVAL '1 DAY'
This works for me - it selects ALL rows with todays Date.

select * from termin where DATE(dateTimeField) = '2015-11-17'
This works well for me!

An easy way of getting only time stamps for the current day since 01:00 is to filter with
CURRENT_DATE + interval '1 hour'
So your query should look like this:
SELECT u.login, u.id, u.first_name
FROM pref_users u
WHERE u.login > u.logout AND
u.login > CURRENT_DATE + interval '1 hour'
ORDER BY u.login;
Hope that helps.

where
u.login > u.logout
and
date_trunc('day', u.login) = date_trunc('day', now())
and
date_trunc('hour', u.login) >= 1

All answers so far are incorrect because they give the wrong answer between 0.00 and 1.00. So if you happen to run the query in that time period you get no results. Based on #ErwinBrandstetter's answer, what you want is this:
WHERE u.login > u.logout
AND u.login >= CASE WHEN NOW()::time < '1:00'::time THEN NOW()::date - INTERVAL '23 HOUR' ELSE NOW()::date + INTERVAL '1 HOUR' END;
I would love to do without the conditional but found no way to.
Edit: #ErwinBrandstetter did do it without a conditional, leaving this here for completeness.

Related

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: Date Calendar Days Interval Scenario

I would like to print this table (displaying only 4 rows for brevity):
Dates
Period
01-MAR-2022
61
02-MAR-2022
61
03-MAR-2022
61
30-APR-2022
61
So far I have:
SELECT CAST(TRUNC(date_trunc('month',CURRENT_DATE) + interval '-2 month') AS DATE) + (n || 'day')::INTERVAL AS Dates
, date_trunc('month',CURRENT_DATE) + interval '-2 month' + INTERVAL '2 month' - date_trunc('month',CURRENT_DATE) + interval '-2 month' AS Period
FROM generate_series(0,61) n
Please help with a better way of generating the period and also replacing the hard-coded 61 in generate_series(0,61).
Thanks!
What are you actually trying to accomplish, it is not clear nor specified. BTW your query is invalid. It appears you looking to list each data from first date of 2 months prior to the last date of 1 month prior and the total number of days in that range. The following would give the first date, and using date subtraction gives the number of days.
with full_range( first_dt, num_days) as
( select date_trunc ('month', (current_date - interval '2 months'))::date
, date_trunc ('month', (current_date - interval '1 day'))::date -
date_trunc ('month', (current_date - interval '2 months'))::date
)
select *
from full_range;
With that in hand you can use the num_days with generate series with the expression
select generate_series(0, num_days-1) from full_range
Finally combine the above arriving at: (see demo)
with full_range( first_dt, num_days) as
( select date_trunc ('month', (current_date - interval '2 months'))::date
, date_trunc ('month', (current_date - interval '1 day'))::date -
date_trunc ('month', (current_date - interval '2 months'))::date
)
select (first_dt + n*interval '1 day')::date, num_days
from full_range
cross join (select generate_series(0, num_days-1) from full_range) gn(n);

Get first date of previous month

Is there any way to get the first day of previous month other than
date_trunc('month', current_date - interval '1 month') ?
I'm trying to save a query in a Report Designer software (DBxtra) but the software freezes while using the "interval" feature of PostgreSQL.
You can try to calculate the previous month manually.
One approach is extract the month and subtract 1 if it is not 12(in this case you return 1):
SELECT to_timestamp(concat(EXTRACT(YEAR from current_date), '-',CASE (EXTRACT(MONTH from current_date)) WHEN 12 THEN 1 ELSE (EXTRACT(MONTH from current_date)-1) END,'-', 1), 'YYYY-MM-DD');
If you need it without timezone:
SELECT to_timestamp(concat(EXTRACT(YEAR from current_date), '-',CASE (EXTRACT(MONTH from current_date)) WHEN 12 THEN 1 ELSE (EXTRACT(MONTH from current_date)-1) END,'-', 1), 'YYYY-MM-DD')::timestamp without time zone;
Try:
make_interval(month := 1)
'1 month'::interval
cast('1 month' as interval)
instead of interval '1 month'

Compare day in current month to same day previous month PostgreSQL

I'm trying to compare values of current month's data to previous months using PostgreSQL. So if today is 4/23/2018, I want the data for 3/23/2018.
I've tried current_date - interval '1 month' but it is problematic for months with 31 days.
My table is structured as simply as
date, value
Check this example query:
WITH dates AS (SELECT date::date FROM generate_series('2018-01-01'::date, '2018-12-31'::date, INTERVAL '1 day') AS date)
SELECT
start_dates.date AS start_date,
end_dates.date AS end_date
FROM
dates AS start_dates
RIGHT JOIN dates AS end_dates
ON ( start_dates.date + interval '1 month' = end_dates.date AND
end_dates.date - interval '1 month' = start_dates.date);
It will output all end_dates and corresponding start_dates. The corresponding dates are defined by interval '1 month' and checked in both ways:
start_dates.date + interval '1 month' = end_dates.date AND
end_dates.date - interval '1 month' = start_dates.date
The output looks like this:
....
2018-02-26 2018-03-26
2018-02-27 2018-03-27
2018-02-28 2018-03-28
2018-03-29
2018-03-30
2018-03-31
2018-03-01 2018-04-01
2018-03-02 2018-04-02
2018-03-03 2018-04-03
2018-03-04 2018-04-04
....
Note, that there are 'gaps' for days without corresponding dates.
Back to your table, join the table with itself (giving aliases) and use given join condition, so the query would look like this:
SELECT
start_dates.value - end_dates.value AS change,
start_dates.date AS start_date,
end_dates.date AS end_date
FROM
_your_table_name_ AS start_dates
RIGHT JOIN _your_table_name_ AS end_dates
ON ( start_dates.date + interval '1 month' = end_dates.date AND
end_dates.date - interval '1 month' = start_dates.date);
Given the following table structure:
create table t (
d date,
v int
);
After populating with some dates and values, there is a way to find the value of the previous month using simple calculations and the LAG function, without resorting to joins. I am not sure how it compares from a performance perspective, so please run your own tests before selecting which solution to use.
select
*,
lag(v, day_of_month) over (order by d) as v_end_of_last_month,
lag(v, last_day_of_previous_month + day_of_month - cast(extract(day from d - interval '1 month') as int)) over (order by d) as v_same_day_last_month
from (
select
*,
lag(day_of_month, day_of_month) over (order by d) as last_day_of_previous_month
from (
select
*,
cast(extract(day from d) as int) as day_of_month
from
t
) t_dom
) t_dom_ldopm;
You may note that between the 29th and 31st of March, the comparison will be made against the 28th of February, since the same day does not exist in February for those particular dates. The same logic applies to other months with different number of days.

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'