how to perform query in Postresql that returns a data count created grouped by month? - sql

In postgresql, how do I perform a query that returns the sum amounts of rows created of a particular table by month? I would like the result to be something like:
month: January
count: 67
month: February
count: 85
....
....
Let's suppose a I have a table, users. This table has a primary key, id, and a created_at column with time stored in ISO8601 formatting. Last year n number of users were created, and now I want to know how many were created by month, and I want the data returned to me in the above format -- grouped by month and an associated count reflecting how many users were created that month.
Does anyone know how to perform the above SQL query in postgresql?

The query would look something like this:
select date_trunc('month', created_at) as mm, count(*)
from users u
where subscribed = true and
created_at >= '2016-01-01' and
created_at < '2017-01-01'
group by date_trunc('month', created_at);
I don't know where the constant '2017-03-20 13:38:46.688-04' is coming from.
Of course you can make the year comparison dynamic:
select date_trunc('month', created_at) as mm, count(*)
from users u
where subscribed = true and
created_at >= date_trunc('year', now()) - interval '1 year' and
created_at < date_trunc('year', now())
group by date_trunc('month', created_at);

Related

How to get value from DB for specific date?

I have a database table which have field counter that counts number of requests to API (by updating it +1), but I want to get these counts for specific date, (for this month). Is it possible to get it? I am using PostgreSQL.
SQL query
CREATE TABLE IF NOT EXISTS Admin (
id SERIAL PRIMARY KEY,
counter INTEGER NOT NULL DEFAULT 0
created_date TIMESTAMP NOT NULL DEFAULT Now()
);
Thanks in advance.
you can use subquery in two cases:
1- If with each request a field is saved in the database, then you will need the number of all fields per month:
count(counter) -> number of all fields per month.
EXTRACT(MONTH FROM created_date ) = EXTRACT(MONTH FROM Now()) -> date in this month
Query :
select count(counter) as "counter In This month"
from Admin
where created_date in( select created_date from Admin where EXTRACT(MONTH FROM created_date ) = EXTRACT(MONTH FROM Now()));
2- If you update the counter after each request, so that the counter in one day equals the number of all requests on the same day.
sum(counter) -> Total number of all requests per month
EXTRACT(MONTH FROM created_date ) = EXTRACT(MONTH FROM Now()) -> date in this month.
Query :
select sum(counter) as "counter In This month"
from Admin
where created_date in( select created_date from Admin where EXTRACT(MONTH FROM created_date ) = EXTRACT(MONTH FROM Now()));
I would also recommend using date_part function:
SELECT COUNT(counter)
FROM Admin
WHERE date_part('month', created_date) = date_part('month', current_date)
;

Daily Rolling Count of Distinct Users on Different time periods

I am trying to find the most optimal way to run the following query which I need to connect to tableau and visualise. The idea is to count 7 day active users, 30 day active users and 90 day active users for each day. So for today I want who was active and for yesterday and I want who was active within those timeframes.
To clarify users can be active multiple times within my time frames.
A count of 7 day actives users would be the distinct number of users who had a session with in the period todays date and todays date -6. I need to calculate this for every date within the last 6 month.
This is the query I have.
with dau as (
select date_trunc('day', created_date) created_at,
count(distinct customer_id) dau
from sessions
where created_date >= date_trunc('day', dateadd('month', -6, getdate()))
group by date_trunc('day', created_date)
)
select created_at,
dau,
(select count(distinct customer_id)
from sessions
where date_trunc('day', created_date) between created_at - 6 and created_at) wau,
(select count(distinct customer_id)
from sessions
where date_trunc('day', created_date) between created_at - 29 and created_at) as mau,
(select count(distinct customer_id)
from session_s
where date_trunc('day', created_date) between created_at - 89 and created_at) as three_mau
from dau
It takes 30 min to run which seems crazy. Is there a better way to do it? I am also looking into the use of materialised views as a faster way to use this in a dashboard. Would this work?
The result I am looking to get would be a table where the rows are dates within the last 6 months and each column is the count of distinct users on 7, 30 and 90 periods from that date.
Thanks in advance!

How can I calculate an "active users" aggregation from an activity log in SQL?

In PostgreSQL, I have a table that logs activity for all users, with an account ID and a timestamp field:
SELECT account_id, created FROM activity_log;
A single account_id can appear many times in a day, or not at all.
I would like a chart showing the number of "active users" each day, where "active users"
means "users who have done any activity within the previous X days".
If X is 1, then we can just truncate timestamp to 'day' and aggregate:
SELECT date_trunc('day', created) AS date, count(DISTINCT account_id)
FROM activity_log
GROUP BY date_trunc('day', created) ORDER BY date;
If X is exactly 7, then we could truncate to 'week' and aggregate - although this gives
me only one data point for a week, when I actually want one data point per day.
But I need to solve for the general case of different X, and give a distinct data point for each day.
One method is to generate the dates and then count using left join and group by or similar logic. The following uses a lateral join:
select gs.dte, al.num_accounts
from generate_series('2021-01-01'::date, '2021-01-31'::date, interval '1 day'
) gs(dte) left join lateral
(select count(distinct al.account_id) as num_accounts
from activity_log al
where al.created >= gs.dte - (<n - 1>) * interval '1 day' and
al.created < gs.dte + interval '1 day'
) al
on 1=1
order by gs.dte;
<n - 1> is one less than the number of days. So for one week, it would be 6.
If your goal is to get day wise distinct account_id for last X days you can use below query. Instead of 7 you can use any number as you wise:
SELECT date_trunc('day', created) AS date, count(DISTINCT account_id)
FROM activity_log
where date_trunc('day', created)>=date_trunc('day',CURRENT_DATE) +interval '-7' day
GROUP BY date_trunc('day', created)
ORDER BY date
(If there is no activity in any given date then the date will not be in the output.)

How can I get a user's activity count for today and this month in a single SELECT query

In my table I have:
Activity : Date
---------------
doSomething1 : June 1, 2020
doSomething2 : June 14, 2020
I want to be able to make a query so that I can get the following result (assuming today is June 1, 2020):
Today : ThisMonth
1 : 2
I looked at group by but I wasn't sure how to do that without a lot of additional code and I think there's very likely a much simpler solution that I'm missing. Something that will just return a single row with two results. Is this possible and if so how?
you can write subqueries to get data in single row,
Select today , month
from
(
( query to get today's count ) as today,
( query to get month's count ) as month
) t;
yes, u can do group by on dates to get todays nd months count.
Hope this will give u some perception to go on.
Is this what you want?
select array_agg(activity) filter (where date = current_date) as today,
array_agg(activity) filter (where date <> current_date) as rest_of_month
from t
where date_trunc('month', date) = current_date;
This uses arrays so it can handle more than one activity in either category.
Assume you want to query based on a particular date -
select count(case when d.date = :p_query_date then 0 end) day_count
,count(0) month_count
from d -- your table name
where d.date between date_trunc('month', :p_query_date)
and date_trunc('month', :p_query_date + interval '1 month') - interval '1 day'
The above query assumes you have index defined on d.date column. If you have index defined on date_trunc('month', date), the query condition can be simplified to:
date_trunc('month', d.date) = date_trunc('month', :p_query_date)

how to find consecutive user login across week

I'm fairly new to SQL & maybe the complexity level for this report is above my pay grade
I need help to figure out the list of users who are logging to the app consecutively every week in the time period chosen(this logic eventually needs to be extended to a month, quarter & year ultimately but a week is good for now)
Table structure for ref
events: User_id int, login_date timestamp
The table events can have 1 or more entries for a user. This inherently means that the user can login multiple times to the app. To shed some light, if we focus on Jan 2020- Mar2020 then I need the following in the output
user_id who logged into the app every week from 2020wk1 to 2020Wk14
at least once
the week they logged in
number of times they logged in that week
I'm also okay if the output of the query is just the user_id. The thing is I'm unable to make sense out of the output that I'm seeing on my end after trying the following SQL code, perhaps working on this problem for so long might be the reason for that!
SQL code tried so far:
SELECT DISTINCT user_id
,extract('year' FROM timestamp)||'Wk'|| extract('week' FROM timestamp)
,lead(extract('week' FROM timestamp)) over (partition by user_id, extract('week' FROM timestamp) order by extract('week' FROM timestamp))
FROM events
WHERE user_id = 'Anything that u wish to enter'
You can get the summary you want as:
select user_id, date_trunc('week', timestamp) as week, count(*)
from events
group by user_id, week;
But the filtering is tricker. It is better to go with dates rather than week numbers:
select user_id, date_trunc('week', timestamp) as week, count(*) as cnt,
count(*) over (partition by user_id) as num_weeks
from events
where timestamp >= ? and timestamp < ?
group by user_id, week;
Then you can use a subquery:
select uw.*
from (select user_id, date_trunc('week', timestamp) as week, count(*) as cnt,
count(*) over (partition by user_id) as num_weeks
from events
where timestamp >= ? and timestamp < ?
group by user_id, week
) uw
where num_weeks = ? -- 14 in your example