I'm having a problem with my MySQL statement. I need a query that counts the number of comments and the number of topics a user has created. My table structure is something like this:
Table 'users'
-------------
user_id
user_name
...
Table 'topics'
--------------
topic_id
topic_user_id
...
Table 'topiccomments'
---------------------
topiccomment_id
topiccomment_user_id
...
So far I've been able to produce this query:
SELECT
u.user_id,
u.user_name,
COUNT(t.topic_user_id) as topic_count,
COUNT(tc.topiccomment_user_id) as topiccomment_count
FROM
users as u
JOIN topiccomments as tc ON u.user_id = tc.topiccomment_user_id
JOIN topics as t ON u.user_id = t.topic_user_id
WHERE
u.user_id = t.topic_user_id AND
u.user_id = tc.topiccomment_user_id
GROUP BY
u.user_id
This query is executed, but the 'topic_count' and 'topiccomment_count' values are totally wrong and I don't quite understand why.
I was hoping somebody here could help me out?
change to
COUNT(DISTINCT t.topic_id) as topic_count,
COUNT(DISTINCT tc.topiccomment_id) as topiccomment_count
This will count the number of distinct topics and topic comments that match the user ID. Before, you were counting the number of rows in the cross-product of topics and topic comments for a given user.
If it works in your situation, I would refactor this into two queries, one for counting topics and one for topic_comments, since this will be more efficient.
quick shot: try replacing count(field) with count(distinct field)
First of all, you can delete your entire WHERE clause. It is not necessary because you already took care of it in the JOINs.
To fix your issue, use this in your SELECT clause instead of the current COUNT statements your have:
COUNT(DISTINCT t.topic_id) as topic_count,
COUNT(DISTINCT tc.topiccomment_id) as topiccomment_count
You are trying to count the number of topics, or topic comments. Not the number of users (which should always be 1).
The JOINs are probably returning a cartesian product of the topiccomments and topics tables because there is no restriction between their relationship, which could explain why you are getting a high count.
One easy way to tackle this problem is to use correlated subqueries:
SELECT u.user_id,
u.user_name,
SELECT (COUNT(*) FROM topics t WHERE t.id = u.id),
SELECT (COUNT(*) FROM topiccomments tc WHERE tc.id = u.id)
FROM users u;
You can also use COUNT(DISTINCT t.topic_id) and COUNT(DISTINCT tc.topiccomment_id) in your original query as some of the other answers suggest. In fact, that may turn out to be more efficient in terms of performance.
You should be counting the topic and comment ids, not the user_ids of the comment/topic.
SELECT
u.user_id,
u.user_name,
COUNT(DISTINCT t.topic_id) as topic_count,
COUNT(DISTINCT tc.topiccomment_id) as topiccomment_count
FROM
users as u
JOIN topiccomments as tc ON u.user_id = tc.topiccomment_user_id
JOIN topics as t ON u.user_id = t.topic_user_id
GROUP BY
u.user_id
Related
I'm assuming there's a way to do this with MySQL but my experience with relational databases is limited so I'm hoping to get some guidaince.
I have a users, registrations and user_registrations table. I'm want to create a SELECT query on my users table that does a nested select that counts the user_registrations for that user.
So for example, I would be looking to have something like this:
SELECT *, (SELECT COUNT() FROM user_registrations WHERE users.user_id = user_registrations.user_id) FROM users
I think my understanding of nested selects is off and I'm hoping someone could point me in the right direction here. Thanks.
You need to group and include all columns you select from the users table into your group by clause also
SELECT u.id, u.name, COUNT(r.user_id)
FROM users u
LEFT JOIN user_registrations r ON u.user_id = r.user_id
GROUP BY u.id, u.name
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.
I have an elementary question about SQL query with joining the same table twice. It sounds very simple, but I have some troubles with it. I hope, anyone can help me with this issue :)
I have two little tables: "peoples" (columns: id, name, ...) and "likes" (id, who, whom). People may set the "likes" to each other. The relationship is many to many.
I want get the table with peoples likes: count of received "likes", delivered and count of mutual likes.
All is correctly, when I use only one join. But for two joins (or more) MySQL combine all rows (as expected) and I get wrong values in counts. I don't know, how I must use count/sum/group-by operators in this case:( I would like to do this without subqueries in one query.
I used a query like this:
SELECT *, count(l1.whom), count(l2.whom)
FROM people p
LEFT JOIN likes l1 ON l1.who = p.id
LEFT JOIN likes l2 ON l2.whom = p.id
GROUP BY p.id;
SELECT p.id, name,
count(lwho.who) delivered_likes,
count(lwhom.whom) received_likes,
count(lmut.who) mutual_likes
FROM people AS p
LEFT JOIN likes AS lwho ON p.id = lwho.who
LEFT JOIN likes AS lwhom ON lwhom.id = lwho.id
LEFT JOIN likes AS lmut ON lwhom.who = lmut.whom AND lwhom.whom = lmut.who
GROUP BY p.id;
But it's calculated the counts of likes incorrect.
It's issue just for training and performance is not important, but I guess, that three joins in my last query is too much. Can I do it using 2 joins?
Thanks in advance for help.
I surmise that there is a 1:N relationship between people and likes.
One problem with your second query, as far as I can tell, is that the lwhom correlation of likes is joined to lwho via id=id. Basically lwhom is lwho. I'd recommend changing the ON clause for this correlation from lwhom.id = lwho.id to p.id = lwhom.whom.
The counts will still be affected by the JOINs, however. Supposing that you have an ID column in the likes table, though, you could then have each COUNT tally the distinct Like IDs per person – if not, consider just using COUNT(DISTINCT correlation.*) instead.
Digressions aside, the following should hopefully work:
SELECT p.id, name,
count(distinct lwho.id) delivered_likes,
count(distinct lwhom.id) received_likes,
count(distinct lmut.id) mutual_likes
FROM people AS p
LEFT JOIN likes AS lwho ON p.id = lwho.who
LEFT JOIN likes AS lwhom ON p.id = lwhom.whom
LEFT JOIN likes AS lmut ON lwhom.who = lmut.whom AND lwhom.whom = lmut.who
GROUP BY p.id,p.name;
I have an SQL Fiddle here.
Ugh... I really struggle with these mySQL joins...
Here's what I'm after. My current query looks like this.
SELECT profiles.photo, postings.postid, postings.text, postings.date, members.fname, members.lname, members.userid
FROM profiles, postings, members
WHERE postings.wallid=postings.posterid
AND postings.wallid=members.userid
AND postings.wallid=profiles.userid
I'm trying to add in a count(*) of matching records from another table. The other table is called likes, and postings.postid = likes.post_id.
What I've tried (and returns no results) is this...
SELECT profiles.photo, postings.postid, postings.text, postings.date, members.fname, members.lname, members.userid,
(SELECT COUNT(*) FROM likes WHERE postings.postid=likes.post_id)
FROM profiles, postings, members, likes
WHERE postings.wallid=postings.posterid
AND postings.wallid=members.userid
AND postings.wallid=profiles.userid
What I've done here is add the nested SELECT, which I thought would resolve this.
Basically, what I'm asking... given my first query, how can I also obtain the count of the number of records in the likes table where postings.postid = likes.post_id? As always, any help / tips / suggestions is always appreciated.
try that:
SELECT profiles.photo, postings.postid, postings.text, postings.date, members.fname,members.lname, members.userid,
likes.like_count
FROM profiles, members, postings
LEFT JOIN (SELECT post_id, COUNT(*) like_count FROM likes GROUP BY post_id) as likes
ON postings.postid=likes.post_id
WHERE postings.wallid=postings.posterid
AND postings.wallid=members.userid
AND postings.wallid=profiles.userid
First off, it's a lot easier to use the new-style sql syntax for this. Conceptually, it's going to be confusing and tough to do outer joins with that old syntax. Second, you're missing the "profile" table and mistakenly seem to have self-joined the postings table. Try writing your queries more like this:
SELECT
profiles.photo,
postings.postid,
postings.text,
postings.date,
members.fname,
members.lname,
members.userid,
COUNT(DISTINCT like_id) as CountOfLikes
FROM profiles
INNER JOIN postings
ON postings.wallid=profiles.userid
INNER JOIN members
ON members.userid=postings.wallid
LEFT JOIN likes
ON likes.post_id = postings.post_id;
I have a system where, essentially, users are able to put in 3 different pieces of information: a tip, a comment, and a vote. These pieces of information are saved to 3 different tables. The linking column of each table is the user ID. I want to do a query to determine if the user has any pieces of information at all, of any of the three types. I'm trying to do it in a single query, but it's coming out totally wrong. Here's what I'm working with now:
SELECT DISTINCT
*
FROM tips T
LEFT JOIN comments C ON T.user_id = C.user_id
LEFT JOIN votes V ON T.user_id = V.user_id
WHERE T.user_id = 1
This seems to only be getting the tips, duplicated for as many votes or comments there are, even if the votes or comments weren't made by the specified user_id.
I only need a single number in return, not individual counts of each type. I basically want a sum of the number of tips, comments, and votes saved under that user_id, but I don't want to do three queries.
Anyone have any ideas?
Edit: Actually, I don't even technically need an actual count, I just need to know if there are any rows in any of those three tables with that user_id.
Edit 2: I almost have it with this:
SELECT
COUNT(DISTINCT T.tip_id),
COUNT(DISTINCT C.tip_id),
COUNT(DISTINCT V.tip_id)
FROM tips T
LEFT JOIN comments C ON T.user_id = C.user_id
LEFT JOIN votes V ON T.user_id = V.user_id
WHERE T.user_id = 1
I'm testing with user_id 1 (me). I've made 11 tips, voted 4 times, and made no comments. My return is a row with 3 columns: 11, 0, 4. That's the proper count. However, I tested it with a user that hasn't made any tips or comments, but has voted 3 times, that returned 0 for all counts, it should have returned: 0, 0, 3.
The problem that I'm having seems to be that if the table that I'm using for the WHERE clause doesn't have any rows from that user_id, then I get 0 across the board, even if the other tables DO have rows with that user_id. I could use this query:
SELECT
(SELECT COUNT(*) FROM tips WHERE user_id = 2) +
(SELECT COUNT(*) FROM comments WHERE user_id = 2) +
(SELECT COUNT(*) FROM votes WHERE user_id = 2) AS total
But I really wanted to avoid running multiple queries, even if they're subqueries like this.
UPDATE
Thanks to ace, I figured this out:
SELECT
(COUNT(DISTINCT T.tip_id) + COUNT(DISTINCT C.tip_id) + COUNT(DISTINCT V.tip_id)) AS total
FROM users U
LEFT JOIN tips T ON U.user_id = T.user_id
LEFT JOIN votes V ON U.user_id = V.user_id
LEFT JOIN comments C ON U.user_id = C.user_id
WHERE U.user_id = 4
the users table contains the actual information bout the user including, obviously, the user id. I used the user table as the parent, since I could be 100% sure that the user would be present in that table, even if they weren't in the other tables. I got the proper count that I wanted with this query!
As I understand your question. You want to count the total comments + tips + votes for each user. Though is not really clear to me take a look at below query. I added columns for details this is a cross tabs query as someone teach me.
EDITED QUERY:
SELECT
COALESCE(COALESCE(t2.tips,0) + COALESCE(c2.comments,0) + COALESCE(v2.votes,0)) AS `Totals`
FROM parent p
LEFT JOIN (SELECT t.user_id, COUNT(t.tip_id) AS tips FROM tips t GROUP BY t.user_id) t2
ON p.user_id = t2.user_id
LEFT JOIN (SELECT c.user_id, COUNT(c.tip_id) AS comments FROM comments c GROUP BY c.user_id) c2
ON p.user_id = c2.user_id
LEFT JOIN (SELECT v.user_id, COUNT(v.tip_id) AS votes FROM votes v GROUP BY v.user_id) v2
ON p.user_id = v2.user_id
WHERE p.user_id = 1;
Note: This used a parent table in order to get the result of a table which doesn't in other table.
The reason why I use a sub-query in my JOIN is to create a virtual table that will get the sum of tip_id for each table. Also I'm having problem with the DISTINCT using the same query of yours, so I end up with this query.
I know you prefer not using sub-queries, but I failed without a sub-query. For now this is all I can.