Last 12 months, group by week - group-by

I have a table with a column REGDATE, a registration date (YYYY-MM-DD HH:MM:SS). I would like to show an histogram (ExtJS) in order to understand in which period of the years users are signing up. I would like to do this for the past twelve months with respect to the current date and to group dates by week.
Any hints?

FWIW in PostgreSQL, Karaszi has an answer that works, but there is a faster query:
SELECT date_trunc('week', REGDATE) AS "Week" , count(*) AS "No. of users"
FROM <<TABLE>>
WHERE REGDATE > now() - interval '12 months'
GROUP BY 1
ORDER BY 1;
I based this off the work of Ben Goodacre

in MySQL:
SELECT COUNT(*), DATE_FORMAT(regdate, "%X%V") AS regweek FROM table GROUP BY regweek;
or
SELECT COUNT(*), YEARWEEK(NOW(), 2) as regweek FROM table GROUP BY regweek;
in PostgreSQL:
SELECT COUNT(*), EXTRACT(YEAR FROM regdate)::text || EXTRACT(WEEK FROM regdate)::text AS regweek FROM table GROUP BY regweek;

Maybe this?
select to_char(REGDATE,'WW') "Week number",
count(*) "number of signups",
from YOUR_TABLE
where REGDATE > current_date-365
group by to_char(REGDATE,'WW')
order by to_char(REGDATE,'WW')

Hint: (SQL)
SELECT CONVERT (VARCHAR(7), REGDATE, 120) AS [RegistrationMonth]
FROM ...
GROUP BY CONVERT (VARCHAR(7), REGDATE, 120)
ORDER BY CONVERT (VARCHAR(7), REGDATE, 120)

Related

extract days of daterange grouped by month postresql

I have a pickupDate and returnDate in my OrderHistory table. I want to extract the sum of rental days of all OrderHistory entries, grouped/ordered by month. A cte seems to be the solution but I don´t get how to implement it in my query since the cte´s i saw were refering to themselves where it says "FROM cte".
I tried something like this:
SELECT
SUM((EXTRACT (DAY FROM("OrderHistory"."returnDate")-("OrderHistory"."pickupDate")))) as traveltime
, to_char("OrderHistory"."pickupDate"::date, 'YYYY-MM') as M
FROM
"OrderHistory"
GROUP BY
M
ORDER BY
M
But the outcome doesn´t split bookings btw two months (e.g. pickupDate=27th march 2022 and returnDate=03rd of april 2022) but will assign the whole 7 days to the month of march, since the returndate is in it. It should show 4 days in march and 3 in april.
Sorry for the probably very stupid question but I am a beginner. (my code is written in postgresql btw)
PostgreSQL naming conventions
Are PostgreSQL column names case-sensitive?
use legal, lower-case names exclusively so double-quoting is not
needed.
Final result in db fiddle
Add daterange column.
alter table order_history add column date_ranges daterange;
update order_history
with a(m_begin, m_end, pickup_date) as
(select date_trunc('month', pickup_date)::date,
(date_trunc('month', pickup_date) + interval '1 month - 1 day')::date,
pickup_date from order_history)
update order_history set date_ranges =
daterange(a.m_begin, a.m_end,'[]') from a
where a.pickup_date = order_history.pickup_date;
then final query:
WITH A AS(
select
pickup_date,
return_date,
return_date - pickup_date as total,
case when return_date <# date_ranges then (return_date - pickup_date)
else ( date_trunc('month', pickup_date) + interval '1 month - 1 day')::date - pickup_date
end partial_mth
from order_history),
b as (SELECT *, a.total - partial_mth parital_not_mth FROM a)
select *,
case when to_char(pickup_date,'YYYY-MM') = to_char(return_date,'YYYY-MM')
then
sum(partial_mth) over(partition by to_char(pickup_date,'YYYY-MM')) +
sum(parital_not_mth) over (partition by to_char(return_date,'YYYY-MM'))
else sum(partial_mth) over(partition by to_char(pickup_date,'YYYY-MM'))
end
from b;
After trying different things I think I found the best answer to my question, that I want to share with the community:
WITH hier as (
SELECT
"OrderHistory"."pickupDate" as start_date
, "OrderHistory"."returnDate" as end_date
, to_char("OrderHistory"."pickupDate"::date, 'YYYY-MM') as M
FROM
"OrderHistory"
GROUP BY
1, 2, 3
ORDER BY
3
), calendar as (
select date '2022-01-01' + (n || ' days')::interval calendar_date
from generate_series(0, 365) n
)
select
to_char(calendar_date::date, 'YYYY-MM')
, count(*) as tage_gebucht
from calendar
inner join hier on calendar.calendar_date between start_date and end_date
where calendar_date between '2022-01-01' and '2022-12-31'
group by 1
order by 1;
I think this is the simplest solution I came up with.

Fetch records of current month using PostgreSQL query

Suppose I have following data in a table
id createdAt
1 2021-02-26T06:29:03.482Z
2 2021-02-27T06:29:03.482Z
3 2021-03-14T06:29:03.482Z
4 2021-03-17T06:29:03.482Z
I want data of current month. ie, if I generate report in march, I need to fetch results of march, so we need only current month data from table.
wanted output is
id createdAt
3 2021-03-14T06:29:03.482Z
4 2021-03-17T06:29:03.482Z
Anyone please help. Thank you.
You can use date_trunc():
select *
from the_table
where date_trunc('month', createdat) = date_trunc('month', current_timestamp);
date_trunc('month', ...) returns the first day of the month.
However, the above is not able to make use of an index on createdat. To improve performance, use a range query:
select *
from the_table
where createdat >= date_trunc('month', current_timestamp)
and createdat < date_trunc('month', current_timestamp) + interval '1 month'
The expression date_trunc('month', current_timestamp) + interval '1 month' returns the start of the next month (that's way this is compared with <)
You can compare the month and year of a date with the current one. But the index by field will not be used, you can build a separate index by year and month for this.
select *
from your_table
where extract(YEAR FROM createdAt) = extract(YEAR FROM now())
and extract(MONTH FROM createdAt) = extract(MONTH FROM now())

Count records grouped by day that counted by interval

Here is the query
WITH dates AS (
SELECT current_date - serie AS date
FROM generate_series(0, 365, 1) AS serie
), items AS (
SELECT *
FROM items
WHERE created_at BETWEEN now() - interval '6 months' AND now()
)
SELECT dates.date, count(items)
FROM dates
LEFT OUTER JOIN items ON items.created_at::date = dates.date
GROUP BY dates.date
Everything works fine except one thing - I need to somehow replace now() with day in a row.
So for each day calculate items count with conditions based on that day.
Just can't reference it.
Is there any solution for this?
smth like this?
WITH dates AS (
SELECT current_date - serie AS date
FROM generate_series(0, 365, 1) AS serie
)
SELECT dates.date, count(items)
FROM dates
LEFT OUTER JOIN items ON created_at BETWEEN dates.date- interval '6 months' AND dates.date
GROUP BY dates.date;
I came to the following solution, which has the same result as Vao Tsun proposed:
WITH dates AS (
SELECT current_date - serie AS date
FROM generate_series(0, 365, 1) AS serie
), date_intervals AS (
SELECT
(dates.date - INTERVAL '6 months') AS start_date,
dates.date AS end_date
FROM dates
)
SELECT date_intervals.end_date, count(items)
FROM date_intervals
LEFT OUTER JOIN items ON items.created_at BETWEEN date_intervals.start_date AND date_intervals.end_date
GROUP BY 1
ORDER BY 1

Monthly retention in Amazon redshift

I'm trying to calculate monthly retention rate in Amazon Redshift and have come up with the following query:
Query 1
SELECT EXTRACT(year FROM activity.created_at) AS Year,
EXTRACT(month FROM activity.created_at) AS Month,
COUNT(DISTINCT activity.member_id) AS active_users,
COUNT(DISTINCT future_activity.member_id) AS retained_users,
COUNT(DISTINCT future_activity.member_id) / COUNT(DISTINCT activity.member_id)::float AS retention
FROM ads.fbs_page_view_staging activity
LEFT JOIN ads.fbs_page_view_staging AS future_activity
ON activity.mongo_id = future_activity.mongo_id
AND datediff ('month',activity.created_at,future_activity.created_at) = 1
GROUP BY Year,
Month
ORDER BY Year,
Month
For some reason this query returns zero retained_users and zero retention. I'd appreciate any help regarding why this may be happening or maybe a completely different query for monthly retention would work.
I modified the query as per another SO post and here it goes:
Query 2
WITH t AS (
SELECT member_id
,date_trunc('month', created_at) AS month
,count(*) AS item_transactions
,lag(date_trunc('month', created_at)) OVER (PARTITION BY member_id
ORDER BY date_trunc('month', created_at))
= date_trunc('month', created_at) - interval '1 month'
OR NULL AS repeat_transaction
FROM ads.fbs_page_view_staging
WHERE created_at >= '2016-01-01'::date
AND created_at < '2016-04-01'::date -- time range of interest.
GROUP BY 1, 2
)
SELECT month
,sum(item_transactions) AS num_trans
,count(*) AS num_buyers
,count(repeat_transaction) AS repeat_buyers
,round(
CASE WHEN sum(item_transactions) > 0
THEN count(repeat_transaction) / sum(item_transactions) * 100
ELSE 0
END, 2) AS buyer_retention
FROM t
GROUP BY 1
ORDER BY 1;
This query gives me the following error:
An error occurred when executing the SQL command:
WITH t AS (
SELECT member_id
,date_trunc('month', created_at) AS month
,count(*) AS item_transactions
,lag(date_trunc('m...
[Amazon](500310) Invalid operation: Interval values with month or year parts are not supported
Details:
-----------------------------------------------
error: Interval values with month or year parts are not supported
code: 8001
context: interval months: "1"
query: 616822
location: cg_constmanager.cpp:145
process: padbmaster [pid=15116]
-----------------------------------------------;
I have a feeling that Query 2 would fare better than Query 1, so I'd prefer to fix the error on that.
Any help would be much appreciated.
Query 1 looks good. I tried similar one. See below. You are using self join on table (ads.fbs_page_view_staging) and the same column (created_at). Assuming mongo_id is unique, the datediff('month'....) will always return 0 and datediff ('month',activity.created_at,future_activity.created_at) = 1 will always be false.
-- Count distinct events of join_col_id that have lapsed for one month.
SELECT count(distinct E.join_col_id) dist_ct
FROM public.fact_events E
JOIN public.dim_table Z
ON E.join_col_id = Z.join_col_id
WHERE datediff('month', event_time, sysdate) = 1;
-- 2771654 -- dist_ct

Getting Dates by Selecting a week in oracle

I have a textbox with random numbers from 1 to 52 which are week numbers of a calendar and a drop down which mentions as years.
For example if I select 2 in a textbox with year 2014, then I want the dates to be mentioned as 05-1-2014 - 11-1-2014. Is it possible to do it.
Also I have tried one query which doesnt match my requirement
SELECT date_val, TO_CHAR (date_val, 'ww')
FROM (SELECT TO_DATE ('01-jan-2013', 'DD-MON-YYYY') + LEVEL AS date_val
FROM DUAL
CONNECT BY LEVEL <= 365)
Please help.
Try this. Here 2 is the number of week in the year (FirstSunday+(NumberOfWeek-1)*7 as WeekStart, FirstSunday+ NumberOfWeek*7-1 as WeekEnd) and 2014 is a year:
select
FirstSunday+(2-1)*7 as WeekStart,
FirstSunday+ 2*7-1 as WeekEnd
from
(
Select NEXT_DAY(TO_DATE('01/01/'||'2014','DD/MM/YYYY')-7, 'SUN') as FirstSunday
from dual
)
SQLFiddle demo
Try this too,
SELECT start_date,
start_date + 6 end_day
FROM(
SELECT TRUNC(Trunc(to_date('2014', 'YYYY'),'YYYY')+ 1 * 7,'IW')-1 start_date
FROM duaL
);