Generating a series from a predefined date (PG) - sql

I'm trying to generate a series of monthly dates from a starting date, which happens to be the date of the oldest user in my users table.
Whilst I can select some dates quite easily;
SELECT generate_series(
now(),
now() + '5 months'::interval,
'1 month'::interval);
and can select the date I need to start at:
SELECT to_date( to_char(CAST(min(created_at) AS DATE),'yyyy-MM') || '-01','yyyy-mm-dd') from users
How can I combine the two so that I'm selecting every month up until now?

Turns out, it can be even simpler. :)
SELECT generate_series(
date_trunc('year', min(created_at))
, now()
, interval '1 month') AS month;
FROM users;
More about date_trunc in the manual.
Or, if you actually want the data type date instead of timestamp with time zone:
SELECT generate_series(
date_trunc('year', min(created_at))
, now()
, interval '1 month')::date AS month;
FROM users;

Turns out it's pretty simple:
SELECT generate_series(
(SELECT to_date( to_char(CAST(min(created_at) AS DATE),'yyyy-MM') || '-01','yyyy-mm-dd') from users),
now(),
'1 month'::interval) as month;

Related

Postgres Subtract Date Interval in Having

I am new to SQL but am having a (probably obvious) issue. My goal is to show all data in the month before the last dated entry. When executing the code block below to find the date a month ago,
SELECT MAX(created_at) - INTERVAL '1 MONTH' AS date
FROM shopify_view
it returns, '2019-11-27 11:40:06'. Makes sense!
But when I try to get all the date with a date above that value:
SELECT created_at AS date
FROM shopify_view
GROUP BY created_at
HAVING created_at >= MAX(created_at) - INTERVAL '1 MONTH'
ORDER BY created_at
it returns the first date as '2018-04-23 10:57:28'. Does not make sense!
what am I missing? Thank you!!
You should use a subquery
SELECT *
FROM shopify_view
Where created_at >= (SELECT MAX(created_at) - INTERVAL '1 MONTH' AS date
FROM shopify_view)
ORDER BY created_at

PostgreSQL Generate Series that displays rolling trailing 12 months

I'm attempting to create a Generate Series that displays the trailing 12 months based on the current date. Currently, I'm just getting the current month displayed 12 times.
select date_trunc('month',current_date)::date as month
from generate_series(
date_trunc('month', current_date)::date - interval '11 months',current_date, '1 month')
Any help would be greatly appreciated.
Your select overrides the series returned. So all you get is 12 instances (the number of rows returned from the series) of date_trunc('month',current_date)::date, which is always the current month of course.
You probably want this:
select *
from generate_series(
date_trunc('month', current_date)::date - interval '11 months',current_date, '1 month')
Or with an alias:
select dMonths
from generate_series(
date_trunc('month', current_date)::date - interval '11 months',current_date, '1 month') dMonths

How to get date: one month away from a specific date?

I know that I can get the date from today such as
select CURRENT_DATE - INTERVAL '1 months';
But what if I need the first date specified. Something like
select '2017-05-08 00:00:00' - INTERVAL '1 months'?
I tried different things and can't get it to work.
You could use:
select '2017-05-08 00:00:00'::DATE - '1 month'::INTERVAL
/\
|
cast as date
DBFiddle Demo
'2017-05-08 00:00:00' is a string literal. You need to convert it to a date, e.g., by using to_date:
SELECT TO_DATE('2017-05-08','yyyy-mm-dd') - INTERVAL '1 months'

SQL difference between two days in hours per day

I have input: '2017-02-02 11:00:00' and '2017-02-13 15:00:00'
I want to know the difference in hours between these days, but there is a twist: I need to know the hours for each day.
the result would look something like
'2017-02-02', '13'
'2017-02-03', '24'
...
'2017-02-13', '15'
If it was only hours then I would use DATEDIFF, but assuming the twist I have no idea how to start. I would appreciate any idea.
ps: there can be different inputs, for example '2017-02-02 11:00:00' and '2017-02-02 15:00:00'
You can use generate_series to generate all the datetimes with an interval of 1 hour between the start and end dates. Then you can group by the date part to get the number of hours worked each day.
select dt_time::date,count(*) as hours_by_day
from (select generate_series('2017-02-02 11:00:00','2017-02-13 15:00:00',interval '1 hour') as dt_time
) x
group by dt_time::date
order by 1
One way uses generate_series() and some arithmetic:
with dates as (
select gs.dte, $date1 as dte1, $date2 as dte2
from generate_series(date_trunc('day', $date1), date_trunc('day', $date2), interval '1 day') gs(dte)
)
select gs.dte,
(case when dte1 > gs.dte and dte2 < gs.dte then 24
when date_trunc('day', dte2) = gs.dte then 24 - extract(hour from dte1)
else extract(hour from dte2)
end) as hours
from dates;

Generate series of months in a column at postgresql

In postgresql, how can I generate a series of monthly dates by the format 'YYYY-MM', with the oldest being the creation month of the user up to the current month?
something like :
select to_char(dt, 'YYYY-MM')
from generate_series(
date_trunc('month', (select created_at::date from users where id=1234)),
now(),
'1 month'::interval) dt;
You can even do it in a single query level:
SELECT to_char(generate_series(created_at::date
,now(), interval '1 mon'), 'YYYY-MM') AS month
FROM users
WHERE users_id = 123 -- users_id is unique