Counting distinct new users in purchase table (MySQL) - mysql

I'm using metabase to generate client reports on multiple metrics. I have beginner knowledge in SQL but the GUI has helped in building most queries except a few.
I have two tables
User table including timestamp for when user registered and user ID
Purchase table including user IDs (seen in user table)
What I need: Table showing cumulative new users (registered in current month) who have made a purchase in the current month.
I assume joining both tables and then counting distinct ids grouped by day while checking register date should solve this, but I have a very sketchy idea of what the actual query will look like.
One part of the question has been answered here in my opinion - Cumulative distinct count
But how to check against registration date is not coming to me. Any help is appreciated.
User Table Columns
ID, Email, Timestamp (timestamp records date of onboarding)
Purchase Table Columns
ID, User ID, User Email, Product ID, Timestamp (timestamp here is time of purchase)
Edit
Thanks for the comments so far, I've been able to get new user IDs on every day making a purchase in the current month. Now I need to a row with the cumulative sum of these IDs so at the end of the time period, I know how many new users were added.
Here's my current code
SELECT count(DISTINCT p.`user_id`) Users_Activated, date(p.`timestamp`) Day
FROM `purchase` p
INNER JOIN `user` u ON u.`id` = p.`user_id`
WHERE date(u.`timestamp`) BETWEEN {{date1}}
AND {{date2}} AND date(p.`timestamp`) BETWEEN {{date3}} AND {{date4}}
GROUP BY date(p.`timestamp`)
ORDER BY date(p.`timestamp`) ASC

Not knowing the full structure of your tables, I'll give it my best shot.
SELECT u.* -- This will give you all info on all users
FROM users u
INNER JOIN purchases p
ON p.userID = u.ID
WHERE u.registrationDate BETWEEN NOW() - INTERVAL 30 DAY AND NOW()
I think this'll work, given the limited info available. The time interval bit might be a bit different but likely not.

How about
SELECT DISTINCT u.id, u.whatever
FROM user_table u INNER JOIN purchase_table p
ON (u.id = p.userid)
WHERE u.signup >= DATE_FORMAT(NOW() ,'%Y-%m-01')
This should get you the current calendar month's signups who have made a purchase.

Related

MySQL query - get users count of users who have placed FIRST order in current time period

I have two MySQL tables for users and their orders, with this structure (simplified for question):
[ USERS table ]
userid
[ ORDERS table ]
id
user_id
date
I need to make request to get COUNT of users who placed their FIRST order (First invoiced users count) in current period, let say for example in current month of current year.
I use request like this, let's say for "Apr 2019" for this example:
SELECT count(distinct orders.user_id) AS value
FROM orders,
users
WHERE users.userid = orders.user_id
&& DATE_FORMAT(orders.date,"%b %Y") = "Apr 2019"
&& (
SELECT DATE_FORMAT(orders.date,"%b %Y") AS firstorderdate
FROM orders
WHERE orders.user_id = users.userid
ORDER BY date ASC LIMIT 1) = "Apr 2019"
)
What I'am trying to do at last part of query is get first ever user order and check that it's date located inside current period (Apr 2019). As I see this part of request is not correct, because we are checking ALL users and I don't know how to check CURRENT user in overall request for his first order.
Please help with correct MySQL query for getting first time invoiced users count in current period (for ex. month).
If I understand you correctly; you first need to get the first orders ever made for every customer. Than you need to check if their first orders date is in your desired range and get a count of the customers matching your criteria.
So here is how it looks like:
select count(orders.user_id) from orders
inner join
(
select user_id, min(id) as firstOrderID from orders
group by user_id
) as firstOrders
on orders.id=firstOrders.firstOrderID
where orders.date_ between '2019-04-01' and '2019-04-30'
You can check it in this fiddle
For the second part of your question in comments;
You should filter in the inner query like this:
select count(orders.user_id) from orders
inner join
(
select user_id, min(id) as firstOrderID from orders
inner join users on users.user_id=orders.user_id
where users.user_type <> "ihs"
group by user_id
) as firstOrders
on orders.id=firstOrders.firstOrderID
where orders.date_ between '2019-04-01' and '2019-04-30'

WHERE clause behaving in the wrong way

i want to create a weekly report using a php script. in the mysql query of this, i want to take out tables that functioned during the last week by using its timestamp in the meantime get the other values(especially the counts of unique users and overall users) since the creation date of those tables. but at the moment its returning incorrect data in terms of counts where the counts are given only within the last week not since the creation of project.
this happens inside a loop so for the example query im using table table_1
QUERY
SELECT DISTINCT b.ID, name, accountname, c.accountID, status,
total_impr, min(a.timestamp), max(a.timestamp),COUNT(DISTINCT userid)
AS unique_users,COUNT(userid) AS overall_users
FROM table_1 a INNER JOIN logs b on a.ID = b.ID INNER JOIN
accounts c on b.accountID = c.accountID
WHERE a.timestamp > DATE_ADD(NOW(), INTERVAL -1 WEEK

Outputting customers who haven't repeat ordered since a specific date range in MySQL

I have searched around but have not found anything which seems to be totally relevant so I'm asking for some help.
I have a single table which contains orders, people can have multiple orders. I need to be able to select people who purchased in 2 years ago (April 2012) where they haven't purchased since, to identify unique people I am using email address as there is no unique customer ID. Here is the order table fields:
orderid,order date,name,email
I have limited SQL knowledge, but my approach previously has been to output a table of orders from April 2012 and another table from May 2012 to the present date. I then compare the 2 tables to find customers who haven't ordered since.
I can't help but feel like there is a more efficient way to do this in one query. Can anyone help?
Thanks,
Sam.
I would use LEFT JOIN here:
SELECT DISTINCT order1.email
FROM `order` order1
LEFT JOIN (SELECT email FROM `order` WHERE orderdate >= '2012-05-01') order2
ON order1.email = order2.email
WHERE orderdate < '2012-05-01'
AND order2.email IS NULL;
The main query is checking for people who ordered before May 2012, and the LEFT JOIN query is checking (with order2.email IS NULL) for people who have NOT ordered since then.
You can write this query without any join something like this:-
select email
from order
where email not in (select email from order where order_date >"April 2012")
and order_date < "April 2012";
Here, first condition filter outs all customer who have bought in last two years, and from second condition you get the customers who have bought two years ago.
As suggested, query with NOT EXISTS will go like this:
select o1.email
from order o1
where not exists (select 1 from order o2 where o2.order_date > "April 2012" and o1.email = o2.email)
and o1.order_date < "April 2012";

MySQL COUNT Filtering

This is my first post on stackoverflow, although I've used it as a reference for a long time. So thanks for all the guidance you've provided me in the past. I really appreciate it. Here is my issue:
I have two tables, one called USERS and one called SIGNIN
USERS
-----------------
userid | password
SIGNIN
--------------
suserid | date
I would like to count the number of times that a user has signed in over the period of the last week.
Here's what I've got:
SELECT userid, password FROM USERS JOIN (SELECT suserid, COUNT(*) AS logins
FROM signin
WHERE WEEKOFYEAR(date) = WEEKOFYEAR(CURDATE()) && signin.suserid = users.userid)
GROUP BY userid
I just can't wrap my head around how to JOIN a subquery and make it count each individuals' logins (date column) and return an individualized number for each individual. I know that query is totally jacked up but I'm just at that point, you know, where I've become so confused that I just need some guidance.
Any help and direction would be fantastic! I've read so many pages to no avail. Thanks, in advance!
** and thank you for the edits. They'll help in the future when I post again.
Don't try to do a subquery, just do the join and group by user id. Also, you want YEARWEEK so you are matching both the year and week, not just the week from any year.
select userid, count(*)
from users inner join signin on userid=suserid and yearweek(`date`) = yearweek(curdate())
group by userid;
left join instead of inner join if you want results of 0 for users who haven't signed in.
This follows what I assume is your intent of "last week" meaning the week of the current date (by default starting Sunday, but see the optional mode parameter to yearweek).
Note that the users table here is completely optional; you could just do:
select suserid, count(*) from signin
where yearweek(`date`) = yearweek(curdate())
group by suserid;
but I'm guessing you may be getting other columns from user or wanting to exclude signins for deleted users.
sThis should be it:
select suserid, count(suserid)
from signin
where date > NOW() - INTERVAL 1 WEEK
group by suserid;
You don't need a subquery if I understand you correctly.
Something like:
SELECT a.userid, a.password, count(b.date) AS logins
FROM users a
INNER JOIN signin b ON a.userid = b.suserid and WEEKOFYEAR(date) = WEEKOFYEAR(CURDATE())
GROUP BY a.userid, a.password
Sorry - haven't got time to try the query to double check syntax, but hopefully will set you in right direction
Edit: If you want to include users with 0 logins, change to LEFT OUTER JOIN
you don't need a join here. what you need is
SELECT userid, password, (SELECT COUNT(*)
FROM SIGNIN
WHERE WEEKOFYEAR(date) = WEEKOFYEAR(CURDATE()) AND signin.suserid = users.userid) AS logins
FROM USERS WHERE 1 GROUP BY userid;

How can I efficiently calculate the number of actions a user has made in a month?

I have a database with two tables: one table which lists several users, and another table which lists every action those users made, the id of the user who made the action, and the date of the action.
I'm trying to calculate the number of actions each user has made each month. I'm not sure how to efficiently do this: does anyone have any suggestions?
Use MONTH() to extract the month from the DATE and then GROUP BY both MONTH and USER_ID:
SELECT u.user_id, MONTH(a.date), COUNT(*) number_of_actions
FROM users u INNER JOIN actions a ON (u.user_id = a.user_id)
GROUP BY u.user_id, MONTH(a.date)
Also, if the user actions span multiple years, and you want to have different counts for January 2011 and January 2012, group by both YEAR and MONTH instead:
SELECT u.user_id, YEAR(a.date), MONTH(a.date), COUNT(*) number_of_actions
FROM users u INNER JOIN actions a ON (u.user_id = a.user_id)
GROUP BY u.user_id, YEAR(a.date), MONTH(a.date)
If #Joao Silva's answer is too slow, you can maintain counts as actions happen in a separate table in a separate table using a trigger or stored procedure for updates. If a disk based table is too slow, you could use a memory table and rebuild it if the server restarts, or use a Redis instance to keep this information.