How to get last 24 hrs data in postgreSQL - postgresql

I want to get last 24 hrs data. i wrote a query in postgreSQL as follows. But I couldn't get the answer as i expected.
SELECT startdate::timestamp AS startdate,
(DATE_PART('hour',startdate::timestamp)::integer) as hrs,count(guorderid)
FROM ord_entitlement
WHERE DATE_PART('Day',CURRENT_DATE::timestamp - startdate::timestamp) < 1
AND DATE_PART('hour',startdate::timestamp) <= 24
GROUP BY hrs,startdate
ORDER BY startdate

Instead of checking date parts, do the time math to get an interval. Use NOW() to get a timestamptz.
SELECT startdate::timestamp AS startdate,
(DATE_PART('hour',startdate::timestamp)::integer) as hrs,
count(guorderid)
FROM ord_entitlement
WHERE NOW() > startdate::timestamptz
AND NOW() - startdate::timestamptz <= interval '24 hours'
GROUP BY hrs,startdate
ORDER BY startdate
This ensures you will get the last 24 hours no matter what your time zone or daylight savings says. NOW() > startdate::timestamptz ensures you don't accidentally pick up things from the future.

If you use CURRENT_DATE you will not get the time instead use now() function. Try the following,
SELECT startdate::timestamp AS startdate,
(DATE_PART('hour',startdate::timestamp)::integer) as hrs,count(guorderid)
FROM ord_entitlement
WHERE DATE_PART('Day',now() - startdate::timestamptz) < 1
GROUP BY hrs,startdate
ORDER BY startdate

date_part() works like extract(), i.e. they will extract a subfield from the source:
-- they will both yield 9 as result
select date_part('day', date '2015-01-09') "day part of 2015-01-09",
date_part('day', date '2015-02-09') "day part of 2015-02-09";
Extracting day(s) therefore is not suited to select the last 24 hours. Similarly extracting hour(s) will (almost) always yield less than or equal to 24.
Extraction day(s) from interval (that's the result of substracting 2 timestamps) is a little different. The result might depend on, whether the interval is justified, or not:
-- they will both yield 1 as result
select date_part('day', interval '1 day') "day part of 1 day",
date_part('day', interval '1 month 1 day') "day part of 1 month 1 day";
-- they will yield 1, 32 and 397 respectively
select date_part('day', timestamp '2015-02-09' - timestamp '2015-02-08') "interval 1",
date_part('day', timestamp '2015-02-09' - timestamp '2015-01-08') "interval 2",
date_part('day', timestamp '2015-02-09' - timestamp '2014-01-08') "interval 3";
Depending on the fact, that the timestamp subtraction is not giving justified intervals is not the best option, I think. You could use simpler conditions to achieve your goal:
-- if startdate is a timestamp:
where current_timestamp - interval '1 day' <= startdate
-- if startdate is a date:
where current_date - 1 <= startdate
If you want to disallow future dates too (as your question's title suggests), you could use a single between condition:
-- if startdate is a timestamp:
where startdate between current_timestamp - interval '1 day' and current_timestamp
-- if startdate is a date:
where startdate between current_date - 1 and current_date

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.

date range in postgresql for a given period

I have the following records in a table, as image below. The last period is December / 2019.
I would like to list the periods within a range of 2 years (backwards) from the current date.
For example: today 09/10/2019, list periods from 01/01/2017 to 12/12/2019
I have difficulty assembling the query below.
SELECT c_period_id, name, startdate, enddate
FROM adempiere.C_Period
WHERE startdate BETWEEN now() - INTERVAL '2 year' AND now()
order by startdate desc
I am not quite sure what your problem is, but if it is rounding the dates to the year boundary, this might serve:
WHERE startdate >= date_trunc('year', current_timestamp) - INTERVAL '2 years'
AND startdate < date_trunc('year', current_timestamp) + INTERVAL '1 year'

How to truncate a date to the beginning of week (Sunday)?

I need to truncate dates to the start of week, which is Sunday in my case. How can I do this in PostgreSQL? This truncates to Monday:
date_trunc('week', mydate)
If you subtract the dow value (0 for Sundays, 6 for Saturdays) from the current date than you get the previous Sunday which is the begin of your Sunday-based week
demo:db<>fiddle
SELECT
my_date - date_part('dow', my_date)::int
FROM
my_table
Further reading, documentation
You could truncate the date to the week's Monday, then subtract 1 day, e.g:
SELECT (date_trunc('week', now() + interval '1 day') - interval '1 day')::DATE;
date
------------
2019-06-16
As per documentation, date_trunc() accepts values of type date and timestamp and returns a timestamp (thus the cast at the end).

postgres '1 year' equals '360 days'?

Am wondering if anyone else has encountered this or knows information about it.
Today is November 3, 2014 and if i check whether or not November 5, 2013 is within the last year i get different answers depending on how i check: 1 year versus 365 days
select now() - '20131105' as diff,
case when now() - '20131105' <= '1 year' then 'within year' else 'not within year' end as yr_check,
case when now() - '20131105' <= '365 days' then 'within 365 days' else 'not within 365 days' end as day_check
2014-11-03 16:27:38.39669-06; 363 days 16:27:38.39669; not within year; within 365 days
Looks like when querying against November 9 tho, it's ok
select now() as right_now, now() - '20131109' as diff,
case when now() - '20131109' <= '1 year' then 'within year' else 'not within year' end as yr_check,
case when now() - '20131109' <= '365 days' then 'within 365 days' else 'not within 365 days' end as day_check
2014-11-03 16:31:12.464469-06; 359 days 16:31:12.464469; within year; within 365 days
anyone have an idea about this? or is there something about date arithmetic that's funny?
postgres version is 9.2.4
or is there something about date arithmetic that's funny?
It's funny alright, but not in the way that makes you laugh.
Twelve months has to equal a year doesn't it?
=> SELECT '12 months'::interval = '1 year'::interval;
?column?
----------
t
Good. Makes sense. Hmm - wonder how long a month is.
=> SELECT '30 days'::interval = '1 month'::interval;
?column?
----------
t
Fair enough. Suppose they had to pick something.
Hmm - but that means...
=> SELECT '360 days'::interval = '12 months'::interval;
?column?
----------
t
Which seems to imply...
=> SELECT '360 days'::interval = '1 year'::interval;
?column?
----------
t
That can't be right! What they need to do is have a month equal to 30.41666 days. No hang on, what about leap years? Hmm - does this affect weeks? AARGH!
Basically, you can't convert sensibly between time units. There aren't 60 seconds in a minute, or 24 hours in a day, 52 weeks in a year or even 365 days. Unfortunately, humans (particularly customer-shaped humans) like converting between time units so we end up with a mess like this.
PostgreSQL's system is no more loony than any other and in fact is better than most.
I'm not sure what is real problem with this check, but it works other way around:
select now() - interval '1 year' <= date '2013-11-05'
I'm no expert in Postgres, but it can be something with type comparisons, because:
select pg_typeof(now() - date '2013-11-05'),
pg_typeof(now() - interval '1 year')
yields result:
interval, timestamp with time zone
so your example compares interval with interval, but for different scales - days vs year, and my solution compares timestamp with date, which seems to work
UPDATE:
You can check that interval '1 year' when not attached to year (not added to date or timestamp) equals to 360 days:
select interval '1 year' <= interval '359 days',
interval '1 year' <= interval '360 days'
which yields:
f, t
From my understanding you can't just compare random year interval when you don't know year it is attached - always compare dates, and just use interval to create new date object.
select now() - interval '1 year' <= now() - interval '365 days'
t
From www.postgresql.org/docs/current/static/datatype-datetime.html:
Internally interval values are stored as months, days, and seconds. This is done because the number of days in a month varies, and a day can have 23 or 25 hours if a daylight savings time adjustment is involved. The months and days fields are integers while the seconds field can store fractions. Because intervals are usually created from constant strings or timestamp subtraction, this storage method works well in most cases. Functions justify_days and justify_hours are available for adjusting days and hours that overflow their normal ranges.
Because you compare two intervals, PostgreSQL internally normalizes values (like justify_interval()), before comparing:
SELECT INTERVAL '31 days' > INTERVAL '1 mon' -- yields 't'
But, if you apply interval substraction/addition, varying day & month length taken into consideration:
SELECT (timestamptz '2014-11-03 00:00:00 America/New_York' - INTERVAL '1 day') AT TIME ZONE 'America/New_York',
timestamptz '2014-11-03 00:00:00 America/New_York' - timestamptz '2014-11-02 00:00:00 America/New_York' <= interval '1 day';
-- | timestamp | boolean |
-- +---------------------+---------+
-- | 2014-11-02 01:00:00 | f |
So, if you need to test, whether a timestamp/date is within a range, you should manipulate timestampts/dates (or use timestamp/date ranges) & compare those values with <, > or BETWEEN.
SELECT timestamp '2014-11-03 00:00:00' - timestamp '2014-10-03 00:00:00' <= interval '1 mon',
timestamp '2014-11-03 00:00:00' - interval '1 mon' <= timestamp '2014-10-03 00:00:00';
-- | boolean | boolean |
-- +---------+---------+
-- | f | t |

get last three month records from table

How to get last 3 months records from the table.
SELECT *
from table
where month > CURRENT_DATE-120
and month < CURRENT_DATE
order by month;
I have used the above query is it correct? shall I use this for get last 3 month record from the table.
You can use built-in INTERVAL instruction
Check how this works:
SELECT CURRENT_DATE - INTERVAL '3 months'
and you can rewrite your SQL to:
SELECT * from table where date > CURRENT_DATE - INTERVAL '3 months'
(not checked but this should give you an idea how to use INTERVAL instruction)
Try that:
SELECT *
FROM table
WHERE month BETWEEN EXTRACT(MONTH FROM NOW() - INTERVAL '3 months')
AND EXTRACT(MONTH FROM NOW())
ORDER BY month
;
This filters the last 3 calendar months
SELECT * from table where date >= to_char(CURRENT_DATE - INTERVAL '3 months', 'YYYY-MM-01')::date
select date::date
from generate_series((current_date - INTERVAL '1 Month')::date, (current_date - INTERVAL '1 DAY')::date,'1
day'::interval) date
WHERE date >= date_trunc('month', current_date - interval '3' month)
and date < date_trunc('month', current_date)
This will give last three months date list, excluding current months date. Example if current month is November. This list will give use all dates of August, Septemeber and October.