Reputation: 1020
I have a simple question and answer section on my website that allows comments. I currently populate the answers using a loop and a $_GET['id'] value. Here is my query
<?php
try{
$parent=$_GET['id'];
$post_type = "2";
$stmt = $dbh->prepare(
"SELECT p.post_id, p.content, p.author, p.created, pc.comment_id AS comment_id, pc.content AS comment_content
FROM posts AS p
LEFT JOIN posts_comments AS pc
ON p.post_id = pc.parent_id
WHERE p.post_type = :post_type AND p.parent = :parent ");
$stmt->bindParam(':parent', $parent, PDO::PARAM_INT);
$stmt->bindParam(':post_type', $post_type, PDO::PARAM_INT);
$stmt->execute();
$answers_array = array();
while ($answers = $stmt->fetch(PDO::FETCH_ASSOC)) {
$answers_array[]= $answers;
}
}
?>
This returns the following results in an array
Array (
[0] => Array (
[post_id] => 12
[content] => I have an answer
[author] => Author1
[created] => 2012-06-09 21:43:56
[comment_id] =>
[comment_content] => )
[1] => Array (
[post_id] => 13
[content] => My second answer
[author] => Author1
[created] => 2012-06-10 06:30:58
[comment_id] => 35
[comment_content] => 1st comment )
[2] => Array (
[post_id] => 13
[content] => My second answer
[author] => Author2
[created] => 2012-06-10 06:30:58
[comment_id] => 36
[comment_content] => 2nd comment )
[3] => Array (
[post_id] => 13
[content] => My second answer
[author] => Author2
[created] => 2012-06-10 06:30:58
[comment_id] => 37
[comment_content] => 3rd comment )
)
On my question.php page I know I will need to loop through these results with something like
<?php $answer_count = count($answers_array);
for($x = 0; $x < $answer_count; $x++) {
$answers = $answers_array[$x];
}
?>
My question -
I don't know whether to use two separate queries to pull the comments associated with each answer or use the join I have above and build another array with php. I don't know how to do that honestly. If I use the join I would like an array that looks like this but I'm not sure how to build it using a loop in php.
Array (
[0] => Array (
[post_id] => 12
[content] => I have an answer
[author] => Author1
[created] => 2012-06-09 21:43:56
[comment_id] =>
[comment_content] => )
[1] => Array (
[post_id] => 13
[content] => My second answer
[author] => Author1
[created] => 2012-06-10 06:30:58
Array(
[1] => Array (
[comment_id] => 35
[comment_content] => 1st comment)
[2] => Array (
[comment_id] => 36
[comment_content] => 2nd comment)
[3] => Array (
[comment_id] => 37
[comment_content] => 3rd comment))
Once I have an array like that I was thinking I could do a for each inside my original php loop on the question.php page.
Upvotes: 1
Views: 2188
Reputation: 17720
One query is fine. As you have it, and probably the better opton. You have to work out which is more efficient, to let MySQL take the strain, or the network and PHP take the strain. It's a lot better to let PHP take the strain than MySQL, but where MySQL has "inbuilt" features, such as the grouping you desire, then leave the MySQL and save the network traffic.
To make this work: add "ORDER BY p.post_id, pc.comment_id" to your query - this gets the results in order.
Then, if you must build into an array (although you may be able to process directly without using an array, the method would be similar):
$lastPostID = 0;
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if ($lastPostID <> $row['post_id']) {
$lastPostID = $row['post_id'];
$answers[$lastPostID] = array('post_id' => $row['post_id'],
'author_id' => $row['author_id'],
etc
'comments' => array() );
}
$answers[$lastPostID]['comments'][] = array('comment_id' => $row['comment_id'], 'coment' => $row['comment'] etc);
}
Upvotes: 2
Reputation: 1254
You'll want to use a JOIN to return all the results with a single query, otherwise, you'll be making multiple queries, one for each post. You'd have a lot of overhead by issuing many separate queries.
An exception would be if you wanted to return a very small number of post results.
Be sure to ORDER the query by post_id, comment_id.
To iterate through the combined results, it would look something like this:
$post_id = 0;
foreach($rows as $row) {
// See if our post changed
if ($post_id != $row['post_id']) {
// Display the post and post header
..
// Update the current post_id variable
$post_id = $row['post_id'];
}
// Display the comment
}
Upvotes: 0
Reputation: 412
The choice is yours. Each has their advantages and drawbacks. Using a single query, (obviously, single database call and) you only need to loop over your data set once, but you have the potential of returning duplicated data. Using multiple queries, you have only pull back exactly the data you need, but (obviously, multiple database calls and) you have to iterate over multiple sets of data.
Below is a dirty implementation of the single query method (same basic flow applies to the multi-query method except comment building is it's own loop). But the basic idea is there. You have a map of your answers, adding/retrieving them as you iterate the records, and appending the comments.
while ($answers = $stmt->fetch(PDO::FETCH_ASSOC))
{
$post_id = strval($answers['post_id']);
if(!array_key_exists($post_id, $answers_array)) {
$answers_array[$post_id] = array(
'post_id' => $answers['post_id'],
// ... assign other stuff ...
'comments' => array()); //initialize the comments array
}
if(!empty($answers_array['comment_id'])) {
$obj = $answers_array[$post_id];
$obj['comments'][] = array(
'comment_id' => $answers['comment_id'],
'comment_content' => $answers['comment_content']);
}
}
Upvotes: 1