【问题标题】:How to combine these MySQL queries and then access the data correctly如何组合这些 MySQL 查询,然后正确访问数据
【发布时间】:2012-03-01 21:51:02
【问题描述】:

我正在我的应用中构建一个嵌套的评论回复系统。

目前一切都按预期工作,但是我发现自己必须使用多个 MySQL 查询才能检索所需的数据。更糟糕的是,“回复”的查询是在 foreach 循环中。这意味着尽管它目前的表现令人钦佩,但它远非最佳,并且会随着数据集的增长而导致问题。

因此,我希望在深入开发之前解决这个问题。

由于应用程序的表格与网站的 wordpress 博客共享相同,因此我使用 wordpress 速记进行查询。

当前页面生成方式如下:

查询一个 cmets 表并检索与一个 projectid 相关的所有结果:-

    $commentquery = "select projects_comments.*, users.user_url, users.display_name
                 from ".$wpdb->prefix."projects_comments projects_comments
                 left join ".$wpdb->prefix."users users on users.ID=projects_comments.userid
                where projectid = '$projectid'
                order by projects_comments.commentid desc
                ";  

$comments = $wpdb->get_results($commentquery);

然后我执行如下的 foreach 循环:-

   if($comments) {
            foreach ( $comments as $c ) 
                { 


                $replyquery = "select project_replies.*, users.user_url, users.display_name

                 from ".$wpdb->prefix."project_replies project_replies
                 left join ".$wpdb->prefix."users users on users.ID=project_replies.uid
                where project_replies.cid = '$c->commentid' 
                order by project_replies.id desc        
                limit 2         
                ";      

                $replies = $wpdb->get_results($replyquery);

                asort($replies);

                $countquery = "select count(*)

                    from ".$wpdb->prefix."project_replies project_replies
                    where project_replies.cid='".$c->commentid."'
                    ";

                $replycount = $wpdb->get_var($countquery);  

    //generate html here
   }
}

在这个循环中还有两个查询。第一个获取每个评论的回复,但将结果限制为 2(我希望这样做是为了有一个“查看所有回复”按钮,然后如果用户需要它们,则查询数据库以获取其余部分),第二个查询计数回复总数。

然后,还使用上述循环中的第二个嵌套 foreach 为循环中的每个回复生成 html(此处表示在此处生成 html 代码),如下所示:-

if ($replies){

    foreach ( $replies as $r ){

     // generate each reply
    }
}

通过以下方式从这些数组中提取所有数据:

$c->userid, $c->body etc... For the comments
$r->userid, $r->body etc... For the replies.

如果可能的话,我希望保持这种格式。

因此,正如问题开头所述,这一切都很完美,但是我知道通过嵌套回复和计数查询,我执行的查询比必要的多得多。 100 cmets 将生成 100 个回复查询和 100 个计数回复查询等。

感谢本网站上的一些乐于助人的人,我考虑使用联接来一次性获取所有原始数据,以供 cmets 和回复使用。就这样……

$commentquery2 = "SELECT c.commentid, c.userid, c.body as cbody, c.projectid, c.posttime, cu.user_url AS cu_url, cu.display_name AS cu_name,
                    r.*, ru.user_url AS ru_url, ru.display_name AS ru_name
                FROM ".$wpdb->prefix."projects_comments AS c
                LEFT JOIN ".$wpdb->prefix."users        AS cu ON cu.ID = c.userid
                LEFT JOIN ".$wpdb->prefix."project_replies   AS r  ON r.cid = c.commentid 
                LEFT JOIN ".$wpdb->prefix."users        AS ru ON ru.ID = r.uid
                WHERE c.projectid = $projectid
                ORDER BY c.commentid DESC, r.id DESC";   

虽然这确实有效(并且足以让我将该问题标记为已回答),但在将其付诸实践时,我遇到了一些困难。

首先,这会将所有数据作为单独的行检索,这意味着如果我有 5 个 cmets,每个 cmets 有 3 个回复,我实际上会返回 15 行,而不是一个嵌套数据对象,回复嵌套在每个评论行中。

为了解决这个问题,我尝试了一些数组操作,如下所示:

$old_id=NULL;
$comments=array();

foreach($getcomments as $c){

    if($c->commentid !== $old_id){

        $comments[$old_id] = $c;
        $old_id = $c->commentid;

    }


    $comments[$old_id]['replies'][] = $c;


} 

这样做会根据需要给我一个嵌套的数据对象。但是,它不包括回复计数查询,也没有按预期将每组回复限制为 2 个,而是检索所有回复。

最后在 foreach 循环中使用我当前的 html 生成代码:

foreach($comments){

    //generate comment html

    foreach($replies) {

         //generate replies html

    }

}

我似乎无法让它与嵌套数据对象一起正常工作。访问正确的深度回复似乎让我感到困惑。

总而言之,我希望能够删除循环查询,将它们组合成一个更大且更高效的查询,或者最坏的情况是一个数据查询和一个单独的计数查询,然后创建一个整齐嵌套的数据对象, cmets 作为行和嵌套在标题“回复”下的任何回复

然后我需要能够在我的 php 代码中正确地遍历这些以生成所需的 html。

对于这个问题的冗长,我深表歉意,并意识到这可能会让你们中的许多人无法回答,但我已经为此奋斗了 19 个小时,真的需要帮助。

非常感谢任何提供任何建议的人。

【问题讨论】:

  • 可能只是将您的表格添加到示例数据中,而您期望获得的结果表格应该更有用。
  • 很可能是莫斯蒂,点了。如果我在 10 分钟开始前还有 2 小时的车程不是那么着急,我会按照你的建议编辑问题。
  • 这已经被报道过几次,包括这篇文章:stackoverflow.com/questions/317322/…
  • 感谢工匠,这很有趣,我没有考虑过......但是,您的链接中描述的嵌套系统是否适合简单的评论/回复系统?既然它永远只有一层深,这不是大材小用吗?或者它仍然会比任何其他方法提供更好的读取性能吗?干杯

标签: php mysql


【解决方案1】:

如果您希望将 cmets 和回复保存在两个不同的表中(请参阅工匠的评论),您可以通过一个简单的技巧来删除循环:从第一个查询中收集评论 ID 并使用一个

WHERE (cid IN (1,2,3,4,...))

而不是循环。如果您需要限制每条评论的回复,那么应该可以使用额外的 WHERE- 或 HAVING 子句。

BurninLeo

【讨论】:

  • 感谢 BurninLeo。虽然这对让我开始有很长的路要走,但我想把这个问题留得更久一点,以便希望获得更多的回应/解决方案。希望你能理解。
  • 我什至不确定这是否真的是您需要的;)我也对其他意见感兴趣。一旦我找到一些时间,我还将阅读在 cmets 中链接到您的问题的线程中链接的嵌套集的介绍......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多