Growth for each quarter+year in SQL over my user table - mysql

I am using MYSQL and I have a User database table where my registered users are stored. I'd love to see how many users have registered on an increasing timeline for each quarter. So maybe Q1 2016 I had 1000 users total, then in Q2 2016 I had 2000 users register, in Q3 2016 4000 total users registered, etc (so I want to see the increase, not just how many registered in each quarter)
From another Stack Overflow post, I was able to create a query to see it by each day:
select u.created, count(*)
from (select distinct date(DateCreated) created from `Users`) u
join `Users` u2 on u.created >= date(u2.DateCreated)
group by u.created
and this works for each day, but I'd like to now group it by quarter and year. I tried using the QUARTER(d) function in mysql and even QUARTER(d) + YEAR(d) to concat it but I still can't get the data right (The count(*) ends up producing incredibly high values).
Would anyone be able to help me get my data grouped by quarter/year? My timestamp column is called DateCreated (it's a unix timestamp in milliseconds, so I have to divide by 1000 too)
Thanks so much

I would suggest using a correlated subquery -- this allows you to easily define each row in the result set. I think this is the logic that you want:
select dates.yyyy, dates.q,
(select count(*)
from Users u
where u.DateCreated < dates.mindc + interval 3 month
) as cnt
from (select year(DateCreated) as yyyy, quarter(DateCreated) as q
min(DateCreated) as mindc
from Users u
group by year(DateCreated), quarter(DateCreated)
) dates;

Related

MYSQL Finding how many users transacted per month

I have been tasked to find how many users performed a transaction in every month in 2020
I know i have two tables to work with.
Table Name: Receipts|Columns: receipt_id, collection_id, user_id, amount
Table Name: Games |Columns: game_id, collection_id, game_date_time
i tried this but I dont think it makes sense or works
select month(games.game_date_time) AS Month, sum(receipts.id) from bills
join games on bills.collection_id = games.collection_id
WHERE YEAR(games.game_date_time) = 2020
group by receipts.user_id, month(games.game_date_time)
order by month(games.game_date_time)
Use COUNT() to get a count, not SUM(). And if you want a count of users, without counting the same user twice, use COUNT(DISTINCT user_id), don't put user_id in the grouping.
SELECT MONTH(g.game_date_time) AS month, COUNT(DISTINCT r.user_id) AS users
FROM receipts AS r
JOIN games AS g ON r.collection_id = g.collection_id
WHERE YEAR(g.game_date_time) = 2020
GROUP BY month
ORDER BY month
find how many users performed a transaction in every month in 2020
SELECT COUNT(r.user_id)
FROM receipts AS r
JOIN games AS g USING (collection_id)
WHERE YEAR(g.game_date_time) = 2020
GROUP BY r.user_id
HAVING COUNT(DISTINCT MONTH(g.game_date_time)) = MONTH(CURRENT_DATE)
This query:
Selects rows for current year only.
For each user - calculates the amount of distinct months for payments for this user and compares with current month. If user has payments in each month (including current!) these values are equal.
Count the amount of users matched this condition.
PS. The query will fail in 2021 - for to receive correct info in future use
HAVING COUNT(DISTINCT MONTH(g.game_date_time)) = CASE YEAR(CURRENT_DATE)
WHEN 2020
THEN MONTH(CURRENT_DATE)
ELSE 12
END

Using SQL to get recent n days activity of every user in the table [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have a table of game activity of users which looks something like this
So,for simplicity just consider account_id and date column. By now you might've understood that each record represents a player playing some game on a specific day. What I want to extract is the recent 15 days activity of every user counting backwards from his last game played. For eg,we have data that ranges from 4th April 2020 to 24 Sep 2020, Let's just say that a user played his last game on 20th Sep 2020 and hasn't played any game since then, so for that user I want his playing activity for the date ranging from 5th to 20th Sep(15 day back from his last game played) and I want to extract the same data for every user.
I've initially thought to implement this like ..... sort the table in descending order based on date and match the date with that specific account when that account_id appears for the first time(to create a dictionary in which key is account_id and value is last date he played) so that I can subtract 15 days from the value and filter the data for every account_id, but my co-worker isn't satisfied with that and is expecting to do all this within a single shot(using SQL query). Can someone guide me on how to do that. Thanks in advance :)
If I understood this correctly, you are basically looking for the MAX(Date) Grouped BY User as your starting (actually end) point.
It's easiest to put this in a subquery or CTE.
Then you can simply query your table again using the last date by user as your end date and calculate that date - 15 days as your start point.
This will retrieve all entries for users in the given period.
Example:
WITH BASE AS(
SELECT
MAX(Date) AS LastDate,
UserID
FROM GameActivity
GROUP BY UserID
)
SELECT
ga.UserID,
ga.Date
FROM GameActivity GA
JOIN BASE B ON b.UserID = ga.UserID
WHERE ga.Date >= DATE_SUB(b.LastDate, INTERVAL 15 DAY)
AND ga.Date <= b.LastDate
EDIT:
For getting the last 15 days regardless of actual dates, I would personally use a Window Function to count back
I split this into 2 CTEs to highlight the logic
WITH DistinctDates AS (
SELECT DISTINCT
user_id,
active_date
FROM userdata
),
DAYCount AS (
SELECT
user_id,
active_date,
COUNT(active_date) OVER (PARTITION BY user_id ORDER BY active_date DESC) AS ActiveDays
FROM DistinctDates
)
SELECT
dc.user_id,
ud.active_date,
dc.ActiveDays
FROM DayCount DC
JOIN userdata UD ON ud.user_id = dc.user_id AND ud.active_date = dc.active_date
WHERE ActiveDays BETWEEN 1 AND 15
ORDER BY dc.user_id, dc.ActiveDays ;
I tried this on MS SQL Server but MySQL should work the same
If you are running MySQL 8.0, you can do this with window functions:
select *
from (
select t.*, max(date) over(partition by account_id) max_date
from mytable t
) t
where date >= max_date - interval 15 day
In earlier versions, an alternative is a correlated subquery:
select *
from mytable t
where date >= (select max(t1.date) from mytable t1 where t1.account_id = t.account_id) - interval 15 day
Or using a join:
select *
from mytable t
inner join (select account_id, max(date) max_date from mytable group by account_id) m
on t.date >= m.max_date - interval 15 day

SQL how to find the average users from each category on a typical date

I have a user table as below;
Column Name Column Datatype Column Description
user_id varchar Unique user id
reg_ts timestamp Registration date
reg_device varchar Device registered
reg_attribution varchar Acquisition type
I am trying to find "On a typical day, what share of registrants are coming from each acquisition
source?"
I wrote the code below but not sure how to divide by the total number of records:
select reg_ts as registiration_date,
reg_attribution as acquisition_type,
count(*)
from users
group by 1,2
order by 1 asc
After I run the code above, I get only get the count of each acquisition type for each date. But I need to find the share of registrants are coming from each acquisition type. Can you please help me fix my query?
You can use a correlated subquery that gets the count for a day (assuming that reg_ts is a day despite being a timestamp).
SELECT u1.reg_ts AS registiration_date,
u1.reg_attribution AS acquisition_type,
count(*) / (SELECT count(*)
FROM users u2
WHERE u2.reg_ts = u1.reg_ts) AS share
FROM users u1
GROUP BY u1.reg_ts,
u1.reg_attribution
ORDER BY u1.reg_ts ASC;
Edit:
If you want the ratio in regard to the total number of users rather than users that registered that day just remove the WHERE clause from the subquery.
SELECT u1.reg_ts AS registiration_date,
u1.reg_attribution AS acquisition_type,
count(*) / (SELECT count(*)
FROM users u2) AS share
FROM users u1
GROUP BY u1.reg_ts,
u1.reg_attribution
ORDER BY u1.reg_ts ASC;
Use window functions:
select reg_ts as registiration_date,
reg_attribution as acquisition_type,
count(*) / sum(count(*)) over () as ratio
from users
group by 1, 2
order by 1 asc;
These have been available in MySQL version 8.0.

MySQL - How to list all volunteers who worked no more than once per calendar year

I have a database of volunteer worker sessions going back several years. Each entry contains, among other things, the name of a volunteer, the date of a session, and the number of hours worked that day. (Yes, volunteers are identified by name only, with no protection against matching names. I didn't set this up, unfortunately.) I want to get a list of all volunteers who appear, at most, once in each calendar year. (AKA "episodic" volunteers.) How would I write this query?
select * from USERS where id in (
select u.id from
(
select
u.id, count(*)
from
USERS u
where
YEAR(date) = YEAR(CURDATE())
group by
name
Having
Count(name) <= 1
))
I couldn't test this out, but i guess this is what you want.
This might help you:
SELECT `name`,
COUNT(`name`) AS `value_occurrence`
FROM `my_table`
WHERE YEAR(START_DATE) = YEAR(CURDATE()
GROUP BY `name`
ORDER BY `value_occurrence` DESC
LIMIT 1;
The top record will be most appeared volunteer.

join results of two mysql queries on the same table

I have the intuition that I'm missing something simple, so please excuse me if it's a stupid question but I haven't been able to find an answer here.
I'm treating a database with usage behaviors. We have one row per user, with date and time spent (plus other non-relevant info).
I'd like to output a histogram of the number of visits per day, and number of visits that lasted more than a certain time ; ideally I'd like to have that in one query.
For now I have these two queries:
SELECT DATE(date), COUNT(date) AS Number_of_users FROM users GROUP BY DATE(date)
SELECT DATE(date), COUNT(date) AS Number_of_stayers FROM users WHERE timespent>5 GROUP BY DATE(date)
How can I combine them to obtain a result in the form of:
date users stayers
2014-01-01 21 5
2014-01-02 13 0
etc.
Thanks in advance for any help!
You can try using IF, like this:
SELECT DATE(date),
COUNT(date) AS Number_of_users,
SUM(IF(timespent>5,1,0)) AS Number_of_stayers
FROM users
GROUP BY DATE(date)
This should work, or at least show the basic idea of using JOINs:
SELECT DATE(a.date),
COUNT(a.date) AS Number_of_users,
COUNT(b.date) AS Number_of_stayers
FROM users a
LEFT JOIN users b ON (a.date = b.date AND b.timespent>5)