1

現在の状況

データベースに2つのテーブルがあります。1つは投稿用、もう1つは評価用です。これらはMySQLのリレーションとリンクされているため、1つの投稿に0、1、または複数の評価を付けることができますが、1つの評価は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エントリの合計評価を取得することです。すべての評価を手動でループする代わりに、他に2つの方法があります。

  • クエリで合計を計算します。

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

    エントリのリストが届きPostます。各エントリには、すでに合計評価が計算されています。writesこれは、Ratingsテーブルに多くのことがあり、はるかに少ない場合に非常に優れたソリューションですreads

  • もう1つの方法は、テーブルの正規化を破ることですが、readパフォーマンスを向上させることです。あなたがしなければならないことは、Postsテーブルに別の列を追加することです:total_rating。そして、それに応じて変更されるテーブルにTRIGGERオンがあります。INSERTRatingsPosts.total_rating

    この方法には、の要求を単純化するという利点がありPostsます。同時に、Ratingsテーブルを使用して、total_ratingが正しく計算されたことを確認したり、評価に大きな変更があった場合に値を再計算したりできます。たとえば、ユーザーの禁止など、このユーザーによるすべての評価が削除されます。

于 2012-06-01T18:59:10.757 に答える