Getting the number of posts that a user has posted? - mysql

How can I get the number of posts that a user has posted using one MySQL query?
I can't really think of anything but this, but there is no aggregate function on the join. So I'm not sure how to proceed. I am positive that joins will not accomplish what I need.
select a1.username as Username
from `logs` as a1
left join `logs` as a2
on a1.username = a2.username
For example, my logs table is filled with information about posts people have made. I want to find how many posts each user has made, i.e.
Username, Posts
User1 100
User2 200
etc
EDIT: Sorry for not providing enough information.
I have a table called logs and it has two columns. One column is called username and another column is called msg. It basically holds information about posts that people have posted.
For example, let's say someone named Red posts Hello world. It will be saved to the table logs and a new row will be created. username will be Red, and msg will be Hello world
I basically want to get the number of messages that EVERY SINGLE user has posted by their username. I.e. here is an example of what I want
Username Posts
Red 1
Blue 10
Sally 30

try this
SELECT Username, count(Posts)
FROM `logs`
GROUP BY Username;
Good luck.

I'm assuming that when you say you "can't use count(*) in a join", you mean that you tried and saw that it didn't work, rather than you can't use COUNT at all. So I'm using it here.
You're right that a JOIN is the wrong place for a COUNT. You want it up in the SELECT column list, and a GROUP BY down below. Aggregate by Username, and count the number of entries in each aggregate.
SELECT Username, COUNT(*) AS Count
FROM logs
GROUP BY Username

This query may help you, change this query as for your requirement
SELECT users.*, count( posts.user_id )
FROM posts LEFT JOIN users ON users.id=posts.user_id
GROUP BY posts.user_id
may be like
SELECT users.username, count( logs.username ) as posts
FROM users LEFT JOIN logs ON users.username=posts.username
GROUP BY users.username

Related

SQL query for finding the two teachers who have access to most number of course rooms

I am a newbie with sql queries so I have no clue how to create an accurate SQL.
I tried my best but I literally cannot find any similar example online, please help me out here.
The Data Schema as follows:
User(userID, username password, email, , userType)
Course(courseID, courseTitle)
Enroll(userID, courseID)
course rooms that users can access; note that users include all sorts of users such as teachers and administrators
Material(materialID, materialText, teacherUserID, courseID)
Question:
Find the two teachers who have access to most number of course rooms. Should there be a tie break, choose the ones with smaller user IDs. List the user ID, email, and the number of course rooms that s/he can access for the two teachers.**
The problems are:
SELECT userid, email, MIN (userid)
How can I specifically find the 2 smaller user IDs and which table should I select for finding out the course rooms? Do I have to use COUNT in this case?
FROM user JOIN enroll ON (user.usertype=enroll.userid)
As the enroll_table cannot identify whether the userID is teacher or administrator, if I use JOIN, can I find the the result that I want?
WHERE....
I don't know how to specifically find two teachers AND make sure they have tie break
Do I have to use GROUP BY and ORDER BY as well?
Just saw your attempted query. Look up how to format the code, so it stands out from the text. But you started about right. While we don't have the full info, try the following:
select user.userid,user.username, count(*) as cnt
from enroll
join user on user.userid=enroll.userid
where user.usertype="teacher"
group by user.userid
order by cnt DESC;
So Mary teaches three courses and comes out ahead. Since you want only the top two you can add the line LIMIT 2 to just get the two most prolific teachers.
The part that is hardest to understand for beginners is the group by clause, which generates aggregation, and which requires something like a count(*) clause in the first line. Read up on this separately and make yourself an even smaller example so you understand this well.
kenken068 also asked for a "tie break" using the userid so maybe the "order by" should be
order by cnt DESC, userid ASC;
Problem 1?
Limit to 2 based on the order on total. And also userid as tie braker.
Problem 2?
That info should be in User.userType
But then you need to know which userType is used for the teachers.
However, teachers have Material?
Problem 3?
See problem 1.
Problem 4?
Not always. But to calculate a total, a count is often used together with a group by.
SELECT
u.userID,
u.email,
COUNT(DISTINCT e.courseID) as TotalCourses
FROM `User` AS u
LEFT JOIN `Enroll` AS e
ON u.userID = e.userID
WHERE u.userID IN (SELECT DISTINCT teacherUserID FROM `Material`)
GROUP BY u.userID, u.email
ORDER BY TotalCourses DESC, u.userID
LIMIT 2
Select teacheruserID, count(courseID) from material
group by teacheruserID;
This will give you the count of courses the teachers have access to.
Then Simply order it in descending with the help of order by desc clause.
and the select TOP 2 with TOP Keyword

How to properly use inner join in SQL when I have to join a table twice?

Note: The actual schema isn't male/female, but some other criteria. I'm just using male/female for this example to make it easier to understand.
I have a table "users", which contains a column user_name and user_gender. The gender can be "M" or "F".
The problem is that I have another table, "messages", that has a column for "sender" and "receiver". These columns contains user_name in each row.
How can I use INNER JOIN so that I can get messages where only males send to females?
I know easily how to specify it once, binding users.user_name to "sender" or "receiver" but not both.
To expand on my question, how do see which top 10 pairs where a male sent the most messages to a female? Note, this means unique A/B pairs, so I want to return cases where a guy sends a single female a ton of messages, not when a guy spams a lot of messages to different females.
Think of your messages table as a "cross table" connecting two rows in the users table. When you join to a table like that, give users two different aliases, and refer to them in your join conditions, like this:
select *
from messages msg
join users m on msg.sender = m.user_id AND m.user_gender='M'
join users f on msg.receiver = f.user_id AND f.user_gender='F'
With this skeleton in hand, you should be able to figure out the rest of your query:
Use GROUP BY to group by m.user_id, f.user_id, and count(*) to count
Order by COUNT(*) to get the highest sender+receiver pairs at the top
Use LIMIT to grab the top ten pairs.

Turn two queries into one

I'm having some problems with a query I'm writing. This seems like table structure that is very frequent so I'd love some help.
Let's say I have 3 tables similar to a facebook structure. Users, Wall Posts, and Comments. Users can make wall posts, and comment on other wall posts.
On a users page I would like to show a users wall posts and a count of how many comments that post has. This is what I have so far
I query the Wall Post table using the users id as an inner join to the User table. That gives me a result set of wall posts for that user's page. Then I loop through that result set, take the Wall Post id from each result set, and query the Comment table for the Count of comments for that Wall Post Id. This works, however I have to hit the db twice. Can anyone think of a way that I could do this with one query?
First Query Example:
SELECT wallPost.*, user.currentDefault, user.displayName, user.userName
FROM wallPost
INNER JOIN user ON user.id = wallPost.sourceUserId
WHERE wallPost.recipientId = ? ORDER BY wallPost.id DESC
Second Query Example:
SELECT COUNT(id) AS count
FROM comment
WHERE wallPostId = ?
I would add the count as a subquery and join the subquery to the main query
SELECT
wallPost.*,
user.currentDefault,
user.displayName,
user.userName,
wallpost_commentcount.total
FROM
wallPost
INNER JOIN user ON user.id=wallPost.sourceUserId
LEFT JOIN (SELECT wallPostId,COUNT(*) as total FROM comment GROUP BY wallPostId) as wallpost_commentcount ON (wallpost_commentcount.wallPostId=wallPost.id)
WHERE
wallPost.recipientId = ?
ORDER BY wallPost.id DESC
Please make sure you have an index on comment.wallPostId otherwise this query will take a long time.
I used the LEFT JOIN because you always want to get the wallPost even if there are no comments records yet

Complex MySQL Query - Find duplicates PER user_id?

I have a database of Facebook Likes from several people. There are duplicate "like_id" fields across many "user_id"s. I want a query that will find the amount of "like_id"s person A has in common with person B.
This query is fantastic for comparing likes when only 2 "user_id"s are in the database, but as soon as I add a 3rd, it messes it up. Basically, I want to see who has the most "likes" in common with with person A.
SELECT *,
COUNT(*)
FROM likes
GROUP BY like_id
HAVING COUNT(*) > 1
Anyone have a query that might work?
This SQL should work. You just need to put in the User A's user_id and it should compare with all other users and show the top matching one. You can change it to show the top 5 or do whatever else you need to do.
Basically what it is doing is that it is doing a self join on the table, but making sure that when it does a join, it is a different user_id but the "like" is the same. Then it does a group by each of the other user_id's and sums the same amount of likes for that user_id.
SELECT all_other_likes.user_id, count(all_other_likes.like_id) AS num_similar_likes
FROM likes original_user_likes
JOIN likes all_other_likes
ON all_other_likes.user_id != original_user_likes.user_id
AND original_user_likes.like_id = all_other_likes.like_id
WHERE original_user_likes = USER_ID_YOU_WANT_TO_COMPARE
GROUP BY all_other_likes.user_id
ORDER BY count(all_other_likes.like_id) DESC
LIMIT 1;
Not sure what database you are using. You might need to do a SELECT TOP 1 if it is MS-SQL, but this is valid PostgreSQL and MySQL syntax.
I think this will do it:
SELECT
likes_a.user_id,
likes_b.user_id
FROM
likes as likes_a JOIN likes as likes_b
ON
likes_a.like_id = likes_b.like_id
WHERE
likes_a.user_id <> likes_b.user_id
And then post-process the results to count up who has the most in common.

Check for a unique value within a count, but get all results

I'm trying to create a single query which, similar to stack overflow, will give me the number of votes, but also make sure that the currently viewing user can't upvote again if they've already upvoted.
my query currently looks like
SELECT cid, text, COUNT(votes.parentid) FROM comments LEFT JOIN votes ON comments.cid=votes.parentid AND votes.type=3 WHERE comments.type=0 AND comments.parentid='$commentParentid' GROUP BY comments.cid
But I'm completely stumpted on how to add the check to see if the userid is in the votes table.
The other option is to add a seperate query where
SELECT COUNT(*) FROM votes WHERE userid='$userid' AND parentid='$commentParentid' AND type=3
I'm just realizing I'm so lost with this that I don't even really know what tags to provide.
SELECT cid, text, COUNT(votes.parentid),
COUNT(IF(votes.userid='$userid',1,NULL)) = 0 AS can_vote
FROM comments
LEFT JOIN votes ON comments.cid=votes.parentid AND votes.type=3
WHERE comments.type=0 AND comments.parentid='$commentParentid'
GROUP BY comments.cid
This should give you a flag can_vote based on the number of times the user has voted on the comment, if you insist on doing this in SQL.