PHP one to many relations - php

I have to table posts and comments have a relation between them i want to display comments of post I display post but I don't know how to display it's commented PHP native help, please

I would be nice if you provide your table structures and the code you have so far. Without those information it is harder to help. ;)
I assume you store the post_id in your comments table? So after you fetch your post in your php-script you will execute a second query on the comments table having your post_id. Sth. like:
Select * From comments WHERE post_id = $postId
make sure that your $postId is safe against SQL injections. Fetch the results in an php array and test if it's empty. If the array isn't empty, you can loop through it with foreach and list the comments.

Your question is not clear, but here is a approx answer
describe your table, displaying comments of a single post is quite easy,
SELECT * from comments WHERE post_id = 123
then use php to loop through comments
e.g
foreach($comments as $comment) {
...
}
OR if you want to get all posts with all comments, here is i created a fiddle for you
http://sqlfiddle.com/#!9/e0264e/1
Help yourself by editing the schema and playing with it

you can use left join to get this relation with post like
example:
SELECT * FROM `posts` WHERE Id=$postId LEFT JOIN `comments` WHERE id = post_id
where the post id field had put in the comments table.
I think this is best than use to separate query

Related

Writing a better code / query

In my website, user's can update and other can comment on the updates, as usual like other social networking websites..
What am doing :
query = fetches first name, last name, user id, update id, update post UNION same details for the user who has logged in i.e /* Updates Of Current Logged In User + Updates Of People He Is Following */
loop {
prints first name last name and update
}
later I introduced commenting feature so now what I do is in the loop I call a query and run a loop again for comments..
loop {
prints first name last name and update
commentquery = fetches firstname, last name, user id, comment, of the particulat post
again loop {
prints first/last name of the person who commented, and his comment
}
}
Now according to me I guess this can be accomplished with the SQL query, that when I retrieve posts, I can fetch it's comments along with it, or is this the right way? the problem is when the outer loop runs, the inner loop also runs to fetch the appropriate comments, so can I join tables to retrieve the comments related to posts/updates?
This is very difficult to answer without your database structure or actual SQL but I have tried to generalise as much as possible. What you are trying to do should be done via SQL with two queries and one loop, something like below.
Edit Your fine looping and re-executing the query. You CAN fetch all this data in one go with SQL but you will duplicate allot of information in each call. For scalability and readability I would stick with two queries and two loops
/** updated after op's comments **/
SELECT data, that, you, want, for, one, post
FROM posts AS a
INNER JOIN users AS b ON b.id = a.user_id
loop over query results () {
/** output the post data **/
/** Then select the users who have posted on this post **/
SELECT a.comments, b.username
FROM comments AS a
INNER JOIN users AS b ON b.id = a.id
INNER JOIN posts AS c ON c.id = a.post_id AND c.post_id = '[post id value]'
ORDER BY a.date_posted;
loop comments here {
/** output comments here **/
}
}
I think merging it in only query might be possible but not nice.
But if I understand correctly what you dislike is that the query for the comments is executed with a differen WHERE clause in the loop. You could eliminate that by fetching all the comments for all the updates you are showing in one query before querying the DB for the updates:
query = select all comments for all updates joined with usernames and whatnot
loop{
$comments[postid][] = data
}
After this you do your normal query for the updates and access the comments from the preloaded array instead of from the database. Not sure if this is better solution though. On the upside you have that there is only one query for the updates, and one for the comments, and not one for the updates and one for the comments of each update.(Like 2 queries instead of 11 when you have 10 updates). Not sure if the difference is really big.
The downside is, that the code you had before was a little more obvious, and so easier to read for someone else.

Multi Threaded Comments PHP?

I have a script I wrote I while back for comments, but it is only single threaded. I would like it to be multi-threaded, but only as so a user can reply to a comment, not so a user can reply to a comment of a comment. So the threads would only be two deep.
Currently I store a comment_id against a user_id in my database.
The only way I can think of to do the multi threaded comments, is to have a parent field in the comments table. But if I do this then when I am selecting the comments with PHP, I will have to do another SELECT command to select the comments children (if any) for each comment. Seems like a lot of work on the database.
There has to be a better way. Any ideas on this? Or tutorials?
There are three (four) alternative possibilities:
A recursive query to select all comments based on their parent ids. This is supported by many database products and the syntax depends on the database type. Check the docs for more info (search for 'recursive').
If you store the article id in each (sub-)comment, you can just select all comments with the article id in one regular select query. You can use the parent ids to properly display the comments on the page under the right parent comment:
SELECT * FROM comments WHERE article_id = :article_id
If you only need two levels of comments, you can use an extended where to include both first level and second level comments:
SELECT * FROM comments
WHERE parent_id = :article_id
OR parent_id IN (SELECT id FROM comments WHERE parent_id = :article_id)
It is also possible to use union all to combine two queries that have the same columns, but since I assume that all data are from the same table, there is probably no need for it (see the extended where-clause above):
SELECT * FROM comments WHERE parent_id = :article_id
UNION ALL
SELECT * FROM comments WHERE parent_id IN
(SELECT id FROM comments WHERE parent_id = :article_id)
Personally, I would go for option 2 because it is simple (no exotic SQL construct required), efficient (1 query) and flexible (supports as many levels of comments as you like).
1 query is enough for this, you just need to loop the data and store it into an array correctly, then you loop the array and display the comments.
This is a common use for hierarchical, or tree-structure data. I wrote a popular answer to this Stack Overflow question: What is the most efficient/elegant way to parse a flat table into a tree?
I also wrote a presentation describing alternatives for tree-structured data: Models for Hierarchical Data with SQL and PHP.
Another solution that is not included in my presentation is the way Slashdot does threaded comments. They use a parent column like you do, so each comment references the comment it replies to. But then they also include a root column so each comment knows the post it belongs to. There are seldom more than a few hundred comments on a given post, and usually you want to get the whole tree of comments for a given post starting at the top of the comment thread:
SELECT * FROM comments WHERE root = 1234;
Then as you fetch the comments, you can write PHP code to process them into arrays of arrays according to the parent columns (this is what #JanL's answer alluded to). I posted code to do this in my answer to another Stack Overflow question, Convert flat array to the multi-dimentional.
This query might work for you (I did not know your structure, so I guessed at it):
SELECT * FROM comments a
LEFT JOIN comments b ON a.comment_id = b.parent_coment_id
LEFT JOIN comments c ON b.comment_id = c.parent_coment_id
WHERE a.comment_id <> b.comment_id
AND a.comment_id <> c.comment_id
AND b.comment_id <> c.comment_id;

Having some trouble with a mysql query pulling data from multiple tables... logic question

Ill try to keep this simple and to the point. Essentially I have a news feed, and a comments section. The comments section has two tiers: responses and then replies to responses. Basically structured like so for a given news post:
-> comment
---> reply
---> reply
Each comment can have multiple replies. Obviously, the WRONG way to do this is to do an SQL query for every comment to check for replies and list them out. EDIT Comments only have 1 tier of replies, ie replies CANNOT have replies. - Thanks JohnP
My Questions for this kind of query:
Should I keep the comments and replies in separate tables and use a JOIN, or can I keep the replies and comments in the same table and use a qualifier to separate the type?
Should I attempt to sort them using the query or pull all the data into an array and sort & display that way?
My table currently is as follow:
ID (unique, auto increment)
NEWS_ID (ties the comment to a particular news post)
REPLY_ID (ties the comment to a parent comment if it is a reply to another comment)
USER_ID
BODY
PUBLISHED_DATE
Any suggestions from those wiser than me would be greatly appreciated! Im still in the very early stages of fully understanding JOINS and other higher level mysql query structures. (IE: I suck at mysql, but im learning :)
Since you said replies are one level deep..
I would make comments 1 table and have a comment_id field to denote ownership and a news_id field to add the relationship to the news item. This way you can simply query for all comments that match the news_id and sort it by comment_id. And then a wee bit of PHP array magic will get you a sorted list of comments/replies.
So having a look at your current table, you're on the correct path.

Most Efficient Way to Get a Query of Posts based upon if a User Follows Them

Right now I have two tables for getting a timeline of posts that a user follows in MySQL, timeline and follows.
In the 'follows' table, there is the 'follows.follow_From' column, the 'follows.follow_To' columns to show where the follows are from.
In the timeline table, there is a 'timeline.post_From' column containing the author's user ID of the post.
What is the most efficient method of selecting all posts from 'timeline' only where the current user has a "follow" in the 'follows' table? I am currently using a MySQL array, but I don't see it as efficient. Thank you for reading this and your help!
I'm not an expert and it might not be the most efficient but I'd guess:
SELECT follow_To FROM follows WHERE follow_From = 'user-id'
SELECT * FROM timeline WHERE timeline.post_From = (the results above)
e.g. SELECT * FROM timeline WHERE timeline.post_From IN (SELECT follow_To FROM follows WHERE follow_From = 'user-id')
Doing the other way round would definitely be slower because your processing more data then cutting it down. Cutting the data down first then look up is better.

Can this query be done without a loop?

So, basically, I have a MySQL table called 'topics' and another one called 'replies', for example. In table 'topics', there's a field called 'relforum' which relates this topic to a forum section. And in the table 'replies', there's a field called 'reltopic', which relates the reply to a topic. Both tables have an id field, auto_increment primary key.
Now, I want to select all replies from a certain forum. Since 'replies' has no 'relforum' field, my way would be:
Select all topics with 'relforum' equal to that certain forum and loop through them
While in the loop, select all replies from the topic that is being 'processed' right now
Merge all fetch_array results in one multidimensional array, then loop through them.
That's something like this:
$query = mysql_query("SELECT * FROM `topics` WHERE `relforum` = '1'");
while($array = mysql_fetch_array($query)) {
$temp = mysql_query("SELECT * FROM `replies` WHERE `reltopic` = {$array['id']}");
$results[] = mysql_fetch_array($temp);
}
Is there a way to merge all that into fewer queries? Because this process would basically run one query per topic in that forum plus one. That would be too much :P
Adding the relforum field to the replies table is a solution (I'm still designing the DB Part so it's not a problem to add it), but I would like to see if there's a solution.
I'm really not good at SQL things, I only know the basic SELECT/INSERT/UPDATE, and I usually generate the last two ones using PHPMyAdmin, so... I guess I need some help.
Thanks for reading!
You need to learn to use joins. The link below is for SQL server but the theory for mySQl is pretty much the same for basic joins. Please do not use comma-based joins as they are 18 years outdated and are a porr pracitce. Learn to use the ANSII standard joins.
http://www.tek-tips.com/faqs.cfm?fid=4785
In accessing a database, you almost never want to use any looping. Databases are designed to perform best when asked to operate on sets of data not individual rows. So you need to stop thinking about looping and start thinking about the set of the data you need.
SELECT
r.*
FROM
replies r
INNER JOIN
topics t
ON
r.reltopic = t.id
WHERE
t.relforum = 1;
You basically need a join of two tables.
SELECT * FROM `replies`, `topics` WHERE `replies`.`reltopic` = `topics`.`id` AND `topics`.`relforum` = '1';
SELECT r.* FROM replies r, topics t
WHERE t.relforum = 1 AND r.reltopic = t.id
get rid of the backquotes. they're nonstandard and clutter the code
Yes, you should use a join here. However you will need to take greater care processing your result set.
Joins are the essential query in a relational database schema. Add them to your arsenal of knowledge :)

Categories