1

现在的情况

我的数据库中有两张表,一张用于帖子,一张用于评分。这些与 MySQL 中的关系相关联,因此一篇文章可能有 0、1 或多个评级,但一个评级只能应用于一篇文章。

当我获取帖子列表时,我还想获得评分,但不必为 foreach 循环中的每个帖子单独调用数据库。

为此,我尝试使用 SQL 查询来获取所有带有 LEFT JOIN 评分的帖子,以便它返回如下结果:

statusId|statusBody|rating
-----------------------------
1, post1, 0
1, post1, 1
2, post2, 0
3, post3, 1
3, post3, 1

SQL 工作正常,我得到了我要求的数据。

理想情况下,我现在想要实现的是将此表转换为对象集合,每个对象存储帖子信息以及取决于其总评分的值。

使用 PDO 返回数据结果后,这是我用来映射数据的代码:

代码逻辑

我的代码逻辑是这样的:

Get all statuses joined with ratings table

Create empty output array

Loop through PDO result
{
    Create loop specific temp array

    Push first row of result into temp array

    Remove row from PDO result

    Loop through PDO result for objects with matching statusId
    {
        If row matches statusId, add to temp buffer and remove from PDO result
    }

    Take first row of buffer and create status object

    Loop through objects in temp array to calculate ratings and add onto above status object
    Clear temp buffer

    Add status object to output array
}

return output array

实际代码

  try 
  {
     $result = $pdo->query($sql);
     //if($result == false) return false;
     $statuses = $result->fetchAll(PDO::FETCH_CLASS, 'status');
  } 
  catch (PDOException $e) 
  {
     return FALSE;
  }

  if (!$result) {
     return FALSE;
  }

  //create empty output array to be filled up
  $status_output = array();

  //loop through all status
  foreach($statuses as $s1key => $s1value)
  {     
     //initialise temporary array;
     $status_temp_buffer = array();

     //create temp array for storing status with same ID in and add first row
     array_push($status_temp_buffer, $s1value);

     //remove from primary array
     unset($statuses[$s1key]);

     //loop through array for matching entries
     foreach($statuses as $s2key => $s2value)
     {
        //if statusId matches original, add to array;
        if($s2value->statusId == $s1value->statusId)
        {
           //add status to temp array
           array_push($status_temp_buffer, $s2value);

           //remove from primary array
           unset($statuses[$s2key]);
        }

        //stop foreach if statusId can no longer be found
        break;
     }

     //create new status object from data;
     $statObj = $status_temp_buffer[0];

     //loop through temp array to get all ratings
     foreach($status_temp_buffer as $sr)
     {
        //check if status has a rating
        if($sr->rating != NULL)
        {
           //if rating is positive...
           if($sr->rating == 1)
           {
              //add one point to positive ratings
              $statObj->totalPositiveRatings++;
           }

           //regardless add one point to total ratings
           $statObj->totalAllRatings++;
        }
     }

     //clear temporary array
     $status_temp_buffer = NULL;

     //add object to output array
     array_push($status_output, $statObj);
  }

问题

我在使用此代码时遇到的问题是,虽然评分很好,并且它正确计算了每个帖子的评分总数,但它仍然显示重复的帖子有多个评分。

对此的任何帮助将不胜感激,谢谢

4

1 回答 1

1

据我了解,目标是获得每个Post条目的总评分。除了手动循环每个评分,您还可以采取另外两条路径:

  • 计算查询中的总数:

    SELECT SUM(rating) AS total , .. FROM Posts LEFT JOIN .... GROUP BY statusID
    

    您将收到一个Post条目列表,每个条目都已计算出总评分。如果您有很多writestoRatings表,这是一个非常好的解决方案,并且更少reads

  • 另一种方法是打破表规范化,但提高read性能。您需要做的是在Posts表中添加另一列:total_rating. 并在表中有一个TRIGGERon ,这会相应地改变。INSERTRatingsPosts.total_rating

    这种方式的好处是简化了请求Posts。同时,Ratings现在可以使用表来确保total_rating已正确计算,或者重新计算值,如果评级有一些较大的变化:比如禁止用户,这会导致删除该用户所做的所有评级。

于 2012-06-01T18:59:10.757 回答