Adding count(*) from a join to a query - mysql

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;

Related

Why does COUNT(*) does the same as COUNT(column) in this query?

I am finishing a SQL course and they have a query example that I don't quite understand.
I have
these tables
and I need to get how many 'etiquetas' (tags in Spanish), are in each post, so they have this solution:
SELECT posts.titulo, COUNT(*) num_etiquetas
FROM posts
INNER JOIN posts_etiquetas ON posts.id = posts_etiquetas.post_id
INNER JOIN etiquetas ON etiquetas.id = posts_etiquetas.etiqueta_id
GROUP BY posts.id
ORDER BY num_etiquetas DESC;
I have been trying to understand this query and two questions came up:
Why COUNT(asterisk) does the same as COUNT(etiquetas.nombre)? For me only the latter makes sense, I don't quite understand why COUNT(asterisk) works in the given solution, isn't COUNT(*) supposed to count the total number of rows? maybe the issue is that I don't really understand how GROUP BY really works.
Why does deleting this line doesn't change the result? What is its use in the original solution?
INNER JOIN etiquetas ON etiquetas.id = posts_etiquetas.etiqueta_id

PHP & MySQL Distinct results using INNER JOIN, WHERE and OR clauses (filtering duplicates)

I know the question is very old, but it's hard to run a very specific search and situations may still differ in little but crucial ways. I'm trying to figure out the correct mysql query for my forum search script. What I need is to list both topics and posts containing matching strings with a single query, both have to be supplied with respective results from another table (topics and posts). In case of any matches in the topic name there should be only 1 post per each topic, which is the very first one. My initial query thus:
SELECT topics.topic, posts.post
FROM topics
JOIN posts
ON
posts.topic_id=topics.id
WHERE topics.topic LIKE '%$search%'
OR posts.post LIKE '%$search%'
This will return all the posts with matching strings correctly but also a lot of duplicate topics along with as many irrelevant posts as the matching topic contains. Typically one should use GROUP BY in such situation, but it won't do any good here since grouping by either topics.topic or posts.post will be mutually detrimental. I also don't see how SELECT DISTINCT could help any and it doesn't seem to do anything anyway, and LIMIT 1 cannot be applied individually here. As always, my last resort is 2 individual queries, but if a single call is possible I would be very delighted to see it.
Ok everyone, the solution was lots more simple than expected (no sub-queries are necessary after all):
SELECT topics.topic, posts.post
FROM topics
JOIN posts ON posts.topic_id = topics.id
WHERE topic LIKE '%$search%'
GROUP BY topics.id
UNION
SELECT topics.topic, posts.post
FROM posts
JOIN topics ON topics.id = posts.topic_id
WHERE posts.post LIKE '%$search%'
Of course, the SELECT order matters a lot and one little thing can change everything. Thank you all for help and let's hope this will assist others in the future!
Try this:
SELECT t.topic as tpost, ppost = (SELECT post.post FROM posts p WHERE p.topic_id = t.id ORDER BY posts.id LIMIT 1)
FROM topics t
where topics.topic LIKE 'xxx'
union
SELECT t2.topic, p2.post
FROM posts p2
JOIN topics t2 on p2.topic_id = t2.id
WHERE posts.post LIKE 'xxx'
EDIT
Testing of this suggested solution proved a mod is required:
SELECT t.topic as tpost, (SELECT post.post FROM posts p WHERE p.topic_id = t.id ORDER BY posts.id LIMIT 1) as ppost
FROM topics t
where topics.topic LIKE 'xxx'
union
SELECT t2.topic, p2.post
FROM posts p2
JOIN topics t2 on p2.topic_id = t2.id
WHERE posts.post LIKE 'xxx'

use COUNT(*) values from one table to another

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.

Multiple joins on the same table with counting in one query

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.

MySQL JOIN with 3 tables and COUNT() not working

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