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;
Related
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.
Suppose I have two tables, users and posts. Posts has the following fields, userid, postid, etc and userid can appear multiple times as one user can write multiple posts....I'm just trying sort the users table based off the # of occurrences per userid in the posts table. I can get the # of occurrences per user using this
SELECT userid, COUNT(*)
FROM posts
GROUP BY userid;
I would like to use the values under COUNT(*) column, maybe add it to my other table because then I can simply to something like this
SELECT * FROM users
ORDER BY newcolumn ASC;
but I'm having trouble doing that. Or can I do it without having to add an extra column? Hints please. Thanks
Left join is the key here!
SELECT users.userid,count(posts.userid) AS total_count
FROM users
LEFT JOIN posts on posts.userid = users.userid
GROUP BY users.userid
ORDER BY total_count DESC;
We are taking the left join on two tables with same user_id and we are counting the total number of posts per user using group by. Finally sort by count and show results.
try an left join:
select users.userid, [user fields],count(postid) as posts_count
from users
left join posts on posts.userid = users.userid
group by users.userid,[user fields]
order by posts_count desc.
You want to select users (FROM users) but you want to sort based on criteria in another table (COUNT(*) FROM posts) -- therefore you need to use a JOIN
Off-hand I can't seem to recall if "JOIN" or "RIGHT JOIN" or "FULL JOIN" is what you need if you wanted to get a cartesian product of the tables then group and aggregate on a single field, but I can avoid the need to remember with a subquery (hopefully someone will soon post a smaller and smarter answer):
SELECT users.* FROM users
JOIN (
SELECT userid, COUNT(*) as count
FROM posts
GROUP BY userid
) as subquery ON users.id = subquery.userid
ORDER BY subquery.count
Note: I haven't tested this query, but it looks good to me. Again: hopefully someone will post a better answer soon as I'm not doing my due dilligence, but you definitely need a JOIN :)
You could add a post_count column to the users table, but you would also have to update that count column every time a user creates a new post and you would have to build that logic into your application.
Otherwise, it looks like the answer from FallAndLearn will get you what you need.
NOTE: the p_date is supposed to be in dd-mm-yy format but excel decided to be a jerk as displayed it as dd-mm.
Anyways, for my query, I wanted to retrieve the username and a counter for the number of times the user has published a message in a particular month.
This is the code I used:
SELECT users.username, count(*)
FROM publishdate JOIN users
ON publishdate.uid = users.uid
WHERE MONTH(STR_TO_DATE(p_date, '%Y-%m-%d')) = 11
GROUP BY users.username;
When I filter for November, I see that ruby has published twice in that month, but how do I include all users who have published 0 messages into the result?
Thank you all in advance.
You have to use users table on the left side of your query and do LEFT JOIN to publishdate table:
SELECT users.username, count(publishdate.uid)
FROM users
LEFT JOIN publishdate ON publishdate.uid = users.uid AND
MONTH(STR_TO_DATE(p_date, '%Y-%m-%d')) = 11
GROUP BY users.username;
Note: Predicate MONTH(STR_TO_DATE(p_date, '%Y-%m-%d')) = 11 has to appear in the ON clause of the query, otherwise LEFT JOIN will be equivalent to an INNER JOIN operation.
A table users has three columns: id, name, pass.
Another table logins has user_id column, an isright boolean (tinyint) column which says whether the login was successful or not and a date column.
I need a simple left join to get the user's name and his password (1), the last login datetime (successful or not) (2) and the count of the logins for the specific user since his last successful login (3).
(1) and (2) I can achieve using
SELECT name, pass, MAX(date)
FROM users
LEFT JOIN logins ON logins.id = users.id
-- here either "GROUP BY users.id" or "WHERE users.id = 1234"
But (3) seems to be harder. I googled it and found many similar question but none of them was asking on exactly how to count rows after specific condition is true. (It's even more complicated - count the logins for that user, not everyone)
I don't even know how to do it in a separate query (I'd prefer having one query for the 3 things and I suppose I'd have to use a subquery, although I prefer joins).
SQL fiddle with the tables and some data: http://sqlfiddle.com/#!9/a932b
Any ideas?
The straight-forward way is to have two derived tables: One to get the last login date per user, the other to get the last successful login date per user. Then select from users, outer join the two derived tables and look whether the last login was successful and count the (failed) logins after the last successful login. (With another DBMS you would rather use analytic functions that MySQL lacks.)
select
users.name,
users.pass,
(
select max(isright)
from logins
where user_id = students.id and date = last_login.date
) as last_login_successful,
(
select count(*)
from logins
where user_id = students.id and date > last_successful_login.date
) as last_logins_failed
from users
left outer join
(
select user_id, max(date) as date
from logins
group by user_id
) last_login on last_login.user_id = users.id
left outer join
(
select user_id, max(date) as date
from logins
where isright = 1
group by user_id
) last_successful_login on last_successful_login.user_id = users.id;
This gives you four possibilities per user:
The user never tried to login. last_login_successful is null and last_logins_failed is meaningless.
The user's logins all failed. last_login_successful is 0 and last_logins_failed is meaningless.
The user's last login was successful. last_login_successful is 1 and last_logins_failed is meaningless.
The user logged in successfully once, but failed at least th last time they tried. last_login_successful is 0 and last_logins_failed is the number of failures after last successful login.
And here is a fiddle: http://sqlfiddle.com/#!9/57b7d/1.
EDIT: To also count failed logins when a user never logged in: If a user never logged in, their last_login.date is null. In last_logins_failed you want to count all records for which the last login occurred before OR never:
(
select count(*)
from logins
where user_id = students.id and (date > last_successful_login.date
or last_successful_login.date is null)
) as last_logins_failed
I guess you could do something like
select count(*)
from logins as l join users as u on l.user_id = u.id
where l.timestamp > (select max(timestamp)
from logins
where user_id = u.id and isright = 1)
Get the last timestamp of the login that was successful (subquery) for user
then get a count for all the logins where the timestamp is greater than that of the user, this automatically gives you only the unsuccessful logins because you took the last successful one as a reference timestamp/datetime
How about using a view which only has latest login detail with below query
select l.user_id, l.date, l.isright from logins l
where l.date >= (select max(l2.date) from logins l2
where l2.isright=1 and l2.user_id = l.user_id)
I don't know yet how to use joins and whenever I try to use them, my queries won't work.
What I want to to is to show users that have signed up grouped by days.
TABLE USER
user_id
register_date
But what happens if there is a day where there are no sign ups? That day is not shown but I want it to be showed.
select COUNT(a.user_id) as count1, a.register_date as count2
from user a
left outer join user b on a.user_id = b.user_id
GROUP BY a.register_date
I tried to adapt what I wanted from some examples but the previous query does not work since it does not show all the dates.
What I what is the following:
COUNT -> DATE
1 ------- 01-01-2013
0 ------- 02-01-2013
5 ------- 03-01-2013
0 ------- 04-01-2013
0 ------- 05-01-2013
The JOIN that you are doing is unnecessary, as it is not giving you any additional information than if you would do:
select COUNT(a.user_id) as count1,
a.register_date
from user a
group by a.register_date
This should give you the number of users in every register_date that you have in your table. If there are no signups, something like this won't work.
You would have to feed it the dates somehow and then it would be appropriate to use a LEFT JOIN with the table USERS to get the COUNT. Having for example, a table with all the dates you want to query called dateTable you would do:
SELECT t1.date,COUNT(a.user_id)
FROM dateTable t1
LEFT JOIN users a ON t1.date = a.register_date
GROUP BY t1.date;
See this question for instructions on how to create a calendar table, or google sql calendar table on google. There are lots of useful information about this topic.