SQL query for aggreating a related object - php

I have two tables as posts and comments. Each row in comments table has id of the post which it belong to. How can I select, for example, most commented ten posts?

Try this
SELECT p.id, COUNT(c.id) tot
FROM posts p INNER JOIN comments c
ON p.id = c.post_id
GROUP BY p.id
ORDER BY tot DESC
LIMIT 10

you can use group by for this
some query like
SELECT posts, count(comment) as total
from comments group by (post) order by total;

Related

How to get the most commented articles using SQL?

We have 2 tables: articles, comments.
The structure of this tables:
articles(article_id(PK), etc);
comments(comment_id(PK), article_id(FK)).
I need to get a list of the most commented articles.
I used the request:
SELECT articles.article_id, COUNT(comments.article_id)
FROM comments
INNER JOIN articles ON comments.article_id = articles.article_id AND comments.article_id = :article_id.
What should be the request to get an array of data with 3 most commented articles?
Is it really possible to do this with SQL?
You should be able to get what you want with this query:
SELECT articles.article_id, COUNT(comments.article_id) AS num_comments
FROM comments
INNER JOIN articles ON comments.article_id = articles.article_id
GROUP BY articles.article_id
ORDER BY num_comments DESC
LIMIT 3
If you just need the article id, then a join is not necessary:
SELECT c.article_id, COUNT(*) AS num_comments
FROM comments c
GROUP BY c.article_id
ORDER BY num_comments DESC
LIMIT 3
The query below will provide to you a list of articles and the number of comments for each of these articles ordering them in descending order of number_of_comments
SELECT articles.article_id, COUNT(comments.article_id) AS comment_count
FROM articles, comments
WHERE articles.article_id=comments.article_id
GROUP BY articles.article_id
ORDER BY comment_count DESC
there is an easier way, you can add 'n-comments' column on the article table and initialize it to zero, and with your function to submit a comment, update the value of the 'n-comments++' after every comment.
thin every article will contain the number of its comments, and it will be very easy to select the most commented articles by:
"SELECT article_id FROM articles ORDER BY n-comments DESC LIMIT 50"
I think it will be easier and faster, hope it can help

How to join 3 tables with different data between them?

I'm not too good with explaining things, apologies.
I have 3 tables that are similar to the below:
users
id
username
threads
id
title
user_id
lastpost_id
posts
id
content
thread_id
user_id
On a page listing forum threads, I want the username of both the thread author, and the last post author of that thread to be displayed, I'm attempting to achieve this in a single query.
My query looks like this:
SELECT t.*,u.username FROM threads t
INNER JOIN users u ON t.user_id=u.id
INNER JOIN posts p ON t.lastpost_id=p.id
ORDER BY t.id DESC
The first join enables me to get the username of the user id that started the thread.
The second join is what I'm not sure on, it can get me the user id but how do I get the username from that, as a 3rd join?
You can select the same table multiple times if you give it a different alias. You can give the fields aliases too:
SELECT
t.*,
tu.username as threadusername, /* Result field is called 'threadusername' */
p.*,
pu.username as lastpostusername
FROM threads t
INNER JOIN users tu ON t.user_id=tu.id /* thread user */
INNER JOIN posts p ON t.lastpost_id=p.id
INNER JOIN users pu ON p.user_id=pu.id /* post user */
ORDER BY t.id DESC
You can join to a joined table like this:
SELECT t.*,u.username,u2.username FROM threads t
INNER JOIN users u ON t.user_id=u.id
INNER JOIN posts p ON t.lastpost_id=p.id
INNER JOIN users u2 ON p.user_id=u2.id
ORDER BY t.id DESC
Note, I haven't had time to test it, but it should work (at least in MySQL).
I don't know if I got it correctly, but as per my understanding you can have a inner query to fetch the thread ids and then have a outer query to fetch the posts based on the thread id, have a max on post id and group by user id. Also join to user to have the name. Hope that helps.

How to avoid to do 100 queries in this case?

I have created a simple blog in php/mysql that show in homepage latest 100 posts and for every post show the comments's number.
This is the pseudocode:
Mysql query to get latest 100 posts.
While cicle:
Get title and body of each post.
Mysql query to get the comments's number of the post.
Database structure:
Post:
-id
-title
-body
-date
Comments:
-id
-id_post
-id_user
-body
-date
Is there a way to avoid 100 queries ?
It's a fairly straightforward query:
SELECT p.id, p.title, p.body. p.date, COUNT(c.id) AS comment_count
FROM Post p
LEFT JOIN Comments c ON p.id=c.id_post
GROUP BY p.id, p.title, p.body. p.date
ORDER BY p.id DESC
LIMIT 100
(Please note it's untested, take it as a starting point.)
I know it's a common believe that a database is nothing but a fancy file system and SELECT * FROM data is all the SQL you'll ever need to know but investing some time in learning basic SQL it's absolutely worth the effort.
You can write a sql query that JOINS both of your tables together, to return all of the information you want:
SELECT
p.id,
p.title,
p.body,
p.date,
COUNT(c.id)
FROM Post p
LEFT JOIN Comments c ON p.id = C.post_id
GROUP BY p.id, p.title, p.body, p.date
ORDER BY p.date DESC
LIMIT 100
Jeff Atwood has a great visual guide explaining how joins work.
We are effectively selecting the top 100 posts in date order, counting the total comments (if they exist - that's why we use a LEFT JOIN as otherwise, if we use an INNER JOIN, we will ONLY return posts that have comments).
We GROUP BY as that's how COUNT (and other aggregation functions like SUM and AVG work - we need to tell them what the rule is for counting/summing/averaging our rows.
We ORDER BY the post date, in DESCending order (latest first) to ensure we return posts in the order they were made.
The LIMIT 100 statement only returns the first 100 rows in MySql. Change it to any number you wish (a top 10, 50 etc) if you want to vary the number of posts in the summary.
The overall result is that you now have a result set that contains the post information, and the number of comments, all in one query. You can then display these results in your web application any way you see fit.
Just join your tables and then count the number of comments for that post.
SELECT p.id, p.title, p.body, COUNT(pc.id) as comments
FROM Post p
LEFT JOIN Comments pc ON (p.id = pc.id_post)
GROUP BY pc.id_post LIMIT 100
Hope that is what you are after.
Join your posts table with your posts-info tables, and select them at the same time
select p.id,pi.comments from posts as p, post_info as pi where p.id == pi.id
or something like that.
EDIT:
select p.title,p.body,p.date,count(c.id) from post as p, comments as c where p.id == c.id_post
I believe.

MYSQL Join help. Get results based on number of comments in seperate comments table?

Beginner here! I am trying to write a query that will select the 3 most commented on results from a "results" table the comments are stored in a seperate "comments" table.
results
- id
- title
- body
- etc
- etc
comments
- id
- result_id
- user_id
- timestamp
- comment
So I need to select all from results and order by the amount of matches between results.id and comments.result_id but I don't really know where to start!
Thanks a lot for the help, it's much appreciated!
Not tested but you can do something like that
SELECT r.id ,r.title, r.body
FROM results r INNER JOIN (SELECT result_id, count(id) cnt FROM comments GROUP BY result_id) c
ON r.id = c.result_id
ORDER by c.cnt DESC
Perhaps try something like this:
SELECT COUNT(c.id) AS comment_count FROM results r
LEFT JOIN comments c ON r.id=c.result_id
GROUP BY result_id ORDER BY comment_count DESC LIMIT 3;
The following should work:
SELECT r.id, COUNT(r.id) AS comment_count
FROM results r
INNER JOIN comments c
ON results.id = c.result_id
GROUP BY r.id
ORDER BY comment_count DESC
You join the two tables where the id of the result is the same as the referenced result_id from the comments table. Then you group the rows by result_id to remove duplicates. The COUNT() function sums up the grouped rows and displays the number of them.
Then just sort the result based on the generated comment count.
You could use LEFT OUTER JOIN as well, then you would get all results that have no comments as well. If you want this or not depends on your needs.
For a description of SQL joins, check out What is the difference between "INNER JOIN" and "OUTER JOIN"?

Get latest 3 comments for a list of posts

Currently I'm running one query to get all posts for a user, then in the loop for that, I am querying for the latest 3 comments for that particular post. Super inefficient; I'm querying over and over again for every post.
I would like to consolidate my queries so that I query just once for all posts, and just once for all comments for those particular posts. At the moment I have a comma-separated list that I made for all posts for this user (e.g. "1,5,18,9")
posts table:
posts.id
posts.userid
comments table:
comments.id
comments.relid (this is the postid)
comments.userid
The query should use the $posts_list I have, which is the comma-separated list of posts. Or a subselect for all posts for this user, but that seems inefficient since I already have the post list in a string.
Thanks so much for any help!
Try this query -
SELECT p.id, p.userid, c.id, c.userid
FROM posts p
JOIN (
SELECT c1.*, COUNT(*) rank FROM comments c1
LEFT JOIN comments c2
ON c2.relid = c1.relid AND c2.id <= c1.id
GROUP BY c1.relid, c1.id
) c
ON p.id = c.relid
WHERE rank < 4
And add condition you need, i.e. - WHERE p.userid IN (1,5,18,9).

Categories