recursive mysql query to get child/parent results - php

I have a comments table [ again :) ]...
comment_id
comment_parent_id
E.G. if there is comment1 (comment_id=1) and comment2 (comment_id=2) both have comment_parent_id=0 but then if someone replies (adds comment) to comment_id=1 it mean this will be comment3 (comment_id=3 but comment_parent_id=1)..
now to fetch and display all comments and sub-comments, I have to use a second query to check if it has sub comments, but I want to do it with one query, instead of recursive function, that will kill the server if there are 100-200 comments and they have have 1-2 sub-comments..
how can this be done..
thanks for your time..
regards

Table structure
posts
id
post_id
user_id
comments
id
post_id
comment_id
user_id
deleted
replies
id
post_id
reply_id
user_id
deleted
SELECT *
FROM posts p
LEFT JOIN comments c ON c.post_id = p.post_id AND NOT c.deleted
LEFT JOIN replies r ON r.post_id = p.post_id AND NOT r.deleted
WHERE p.user_id = $user_id

Related

Finding username of the last post in mysql table joining 3 tables

I know I am doing this qry wrong - its taking over 10secs for the results to come back w/ only 3000 rows of data...
I have 3 tables:
users
id
username
DATA:
1|tom
2|dick
3|harry
posts
id
id_users
DATA:
1|1
2|1
3|1
4|2
5|2
6|3
cronjobs
id
id_post
id_wall
DATA: id|id_post|id_wall
1|1|1
2|1|2
3|1|3
4|1|4
5|1|5
6|2|5
7|4|3
8|6|3
9|4|4
A user will make a post
That post will be put on one or more walls and stored in the cronjobs table.
The id on cronjobs is auto increment.
I need to get the username and last post on each wall.
In the above example
Dick was the last person to post on wall 4 with post 4
Harry was the last person to post on wall 3 with post 6
Tom was the last person to post on wall 5 with post 2
Tom was the last person to post on wall 2 with post 1
Tom was the last person to post on wall 1 with post 1
Here is the qry im currently using, I know using the IN clause with the select inside it, is killing this....
SELECT
c.id,
c.id_post,
c.id_wall AS id_wall,
p.id_users AS user_id,
u.NAME AS username
FROM
cronjobs c,
posts p,
users u
WHERE c.id IN
(SELECT MAX(id)
FROM
cronjobs
GROUP BY id_wall)
AND c.id_post = p.id
AND p.id_users = u.id
ORDER BY c.id
Any help is appreciated!
Try this
SELECT
c.id,
c.id_post,
c.id_wall AS id_wall,
p.id_users AS user_id,
u.NAME AS username
FROM
cronjobs c,
posts p,
users u ,
(SELECT MAX(id) as id
FROM
cronjobs
GROUP BY id_wall) table_id
where c.id_post = p.id
AND p.id_users = u.id
and table_id.id =c.id
ORDER BY c.id
You can use join instead of a subquery in where clause, subquery in join part will be executed once while subquery in where clause will be executed for all the resultant rows this query will perform much better than yours, also index your columns that appears in on() part
SELECT
c.id,
c.id_post,
c.id_wall AS id_wall,
p.id_users AS user_id,
u.username AS username
FROM
cronjobs c
join (SELECT MAX(id) id ,id_wall
FROM cronjobs
GROUP BY id_wall) c1 on c.id = c1.id and c.id_wall = c1.id_wall
join posts p on c.id_post = p.id
join users u on p.id_users = u.id
ORDER BY c.id
DEMO

Select each first record with id in another table's result

I have two tables, Users(id, username) and Posts(id, user_id, content). I want to list a summary of them which, I want to list all users and the first post of each user. How can I realize this in one query?
I tried something like.
QUERY
SELECT Users.*, Posts.content
FROM Users, Posts
WHERE Posts.user_id=T_Users.id
But it will return all posts for each user (I cannot add LIMIT 1 at the tail of course which only returns one user).
Some sample records:
Users table:
id username
1 test1
2 test2
Posts table:
id user_id content
1 1 This is a test1's content.
2 1 This is another test1's content.
3 2 This is a test2's content.
And I want the result:
Users.id Users.username Posts.content
1 test1 This is a test1's content.
2 test2 This is a test2's content.
Here is one approach to get the latest record per user i assume the latest record will be considered as the minimum post id
SELECT u.*, p.content
FROM Users u
join Posts p on p.user_id=u.id
join (select user_id ,min(id) id from Posts group by user_id ) p1
on (p.id = p1.id and p.user_id = p1.user_id )
Demo
Try this
select min(x.id) as Id,x.user_id,x.content from(
select p.id,p.user_id,p.content from Users u inner join Posts p
on u.id=p.user_id and u.gender=1
)x group by x.user_id
Have you tried group by clause.
SELECT Users.*, Posts.content
FROM Users, Posts
WHERE Posts.user_id=T_Users.id GROUP BY Posts.user_id

List comments by number of likes

I'm trying to get PHP to list out comments by descending number of likes they receive.
Currently, the comments' content and the number of likes they receive are in 2 separate tables: "comments" and "likes".
PHP code:
To get comments from "comments" table:
$this->db->order_by ('comment_id', 'asc');
$data['comment'] = $this->db->select()->get('comment');
To get likes from "likes" table:
$data['like'] = $this->db->get('like');
To show the number of likes for each comment:
$query_like=$this->db->query("select ip from like where comment_id='$comment_id'");
$count_like=$query_like->num_rows();
I'm wondering if it's possible to order the comments by the number of likes they receive without changing the tables' structure. Any advice hugely appreciated.
If I understand the data structure correctly, you just need a join and an aggregation:
select c.*, count(*) as numlikes
from comments c join
upvote l
on c.comment_id = l.comment_id
group by c.comment_id
order by count(*) desc;
EDIT:
To get comments with zero upvotes, do the left outer join in the other direction:
SELECT c.*, count(u.comment_id) as num_upvotes
FROM comment c left join
upvote u
on c.comment_id = u.comment_id
WHERE c.comment_id = '$interview_id'
GROUP BY c.comment_id
ORDER BY num_upvotes DESC;

How to get comments and replies?

I am trying to make a comments and replies to comments for media posted by users.
My comments table is structured like:
commentId : parentCommentId : mediaId : userId : comment
I want to select the most recent 10 original comments and their replies to a mediaId.
To do this I am running 2 sql statements.
SELECT commentId FROM comments
WHERE mediaId='3' AND parentCommentId='0'
LIMIT 10;
(This gets the commentIds of the most recent original 10 posts.
I then use these commentIds in the following)...
SELECT c.*,u.* FROM comments AS c
JOIN users AS u on u.userId=c.userId
WHERE parentCommentId IN --( *****commentIds from previous query***** );
Is there a better way to do this? Perhaphs using a JOIN?
What if you make it this way:
SELECT c.*,u.* FROM comments c
JOIN users u on u.userId=c.userId
JOIN comments p_c on p_c.commentId = c.parentCommentId
WHERE p_c.mediaId='3' AND p_c.parentCommentId='0'
LIMIT 10;
This will be useful for your problem
SELECT c.*,u.* FROM comments AS c
INNER JOIN users AS u on u.userId=c.userId
INNER JOIN comments pc on pc.commentId = c.CommentId
WHERE pc.mediaId='3' AND pc.parentCommentId='0'
LIMIT 10;

joining a count on a query

I have 2 tables: comments & blog
blog has the following fields: id(Unique key),title, author, body, date, img, imgdes, tags
comments : key(Unique key), postid(related to the id of blog),name, email, date, message
Im trying to display all of my blog post and the number of comments on every post.
So im trying to "count(postid) where postid=id"
I got something to work but its based around having 1 comment which wont work but this is it:
SELECT a.postid,c.author,c.title, c.id,c.body,c.date,c.pic, c.tags, c.imgdesc,
COUNT(*) AS num_comments FROM comments a LEFT JOIN blog c ON c.id = a.postid
GROUP BY c.id order by id DESC"
Again this only work when everything has a comment and i get why but i cant figure out how to implement what I want.
To put it all out there i have:
$sql="***( help 1 of 2) what to set the query to****"
$query = mysql_query($sql) or die(mysql_error());
<?php do{ ?>
<html stuff here>
<?php echo $blog['title']?><br>
<?php echo $blog['*******(help 2 of 2) # of comments display here******']
<?php } while($blog = mysql_fetch_assoc($sql));?>
im sure this is a easy join but i have no clue thanks!
Use this query it may works for you
SELECT a.postid,c.author,c.title, c.id,c.body,c.date,c.pic, c.tags, c.imgdesc, COUNT(a.key) AS num_comments FROM blog c left outer join comments a ON a.postid = c.id GROUP BY c.id order by id DESC
if you want all the blog posts then it should be on the left side of the left join.
I think the issue lies where you write: FROM comments a LEFT JOIN blog c ON c.id = a.postid
GROUP BY c.id order by id DESC"
The comments a and blog c don't seem to be correct references.
Should it be FROM comments.a LEFT JOIN blog.c ON ...?
Are you trying to count the number of comments in each blog? if yes then,
SELECT c.postid,count(key) as num_of_comments
FROM blog b, comments c
WHERE b.id = c.postid
GROUP BY c.postid
Another easy way out:
As you have the postid as a foreign key, you can just get the results from comments table
SELECT postid,count(key) as num_of_comments
FROM comments
GROUP BY postid

Categories