将 MySQL 查询结果中的数据按一列进行分组,并从某些列创建子数组,并从另一列获取平均值

问题描述 投票:0回答:2

我需要获得

$product['stars']
的总和,以便我可以用它来求平均值。当我尝试使用它时,我没有在阵列上使用它?我也相信这是一个字符串。需要转换成INT吗?

$categories = array();
while ($row_rsCategories = mysqli_fetch_assoc($res)) { 
    $product_array = array();
    $product_array_query = mysqli_query($mysqli,"SELECT id, user_id, client_id, comments, stars FROM reviews WHERE user_id = '" . $row_rsCategories['userId'] . "'");
    while ($product_array_fetch = mysqli_fetch_array($product_array_query)) {
       $product_array[] = array(
           "id" => $product_array_fetch['user_id'],
           "comments" => $product_array_fetch['comments'],
           "stars" => $product_array_fetch['stars']
       );
    }              

    $categories[] = array(
        'id' => $row_rsCategories['userId'],
        'name' => $row_rsCategories['usersName'],
        'products' => $product_array,
    );
}

foreach ($categories as $category) {
    ?>                  
    <div class="col-md-4">
        <div id = "user-square">  
            <?php    
            echo $category['name'];
            ?>
            </br>
            <?php foreach($category['products'] as $product) {
                echo $product['stars'];
                ?> </br>
            <?php }
php arrays mysqli grouping average
2个回答
2
投票

您可以通过将

array_sum
array_map
组合来做到这一点:

$starsum = array_sum(array_map(function($x) { return $x['stars']; }, $product_array));

但是您也可以在构建结果数组时计算总和:

$starsum = 0;
$rowcount = 0;
while($product_array_fetch = mysqli_fetch_array($product_array_query)) {
    $product_array[] = array("id"=>$product_array_fetch['user_id'],"comments"=>$product_array_fetch['comments'],"stars"=>$product_array_fetch['stars']);
    $starsum += $product_array_fetch['stars'];
    $rowcount++;
}

$categories[] = array(
    'id' => $row_rsCategories['userId'],
    'name' => $row_rsCategories['usersName'],
    'products' => $product_array,
    'avgstars' => ($rowcount == 0) ? 0 : $starsum / $rowcount
);

无需将值转换为整数,当您对它们使用算术函数时,PHP 会自动执行此操作。


0
投票

使用嵌套循环访问数据库并不是一个好习惯。理想情况下,您希望单次访问数据库并收集所有必需的数据。在这种情况下,如果您想要忽略未给予评论的用户,请使用 INNER JOIN;如果您想要包含未给予评论的用户,请使用 LEFT JOIN。您无条件声明

$product_array
表明您应该使用 LEFT JOIN。

无需手动从结果集对象中记录

fetch()
——只需在对象上使用
foreach()
并访问数据,就好像每行都是关联数组一样。

至于按

userId
分组,如果你没有积累
comments
字符串,我建议你使用MySQL的
AVG()
聚合函数。但是,由于您需要更细致的功能,因此需要手动操作来填充评论子数组并跟踪星级和评论计数。我将演示如何将引用推入结果数组,然后仅修改这些引用以更新必要的字段。

代码:(PHPize Demo使用我自己的示例输入数据)

$sql = <<<SQL
SELECT userId,
       usersName,
       comments,
       stars
FROM cats
LEFT JOIN reviews ON cats.userId = reviews.user_id
ORDER BY cats.usersName, cats.userId
SQL;

$result = [];
foreach ($mysqli->query($sql) as $row) {
    if (!isset($ref[$row['userId']])) {
        $ref[$row['userId']] = [
            'id' => $row['userId'],
            'name' => $row['usersName'],
            'comments' => $row['stars'] === null ? [] : [$row['comments']], // if a review, create single-element array
            'stars' => $row['stars'] === null ? [] : [$row['stars']], // if a review, create single-element array
            'reviews' => $row['stars'] === null ? 0 : 1, // if a review, start count at 1
            'starSum' => $row['stars'],
            'average' => $row['stars'],
        ];
        $result[] = &$ref[$row['userId']];
    } else {
        $ref[$row['userId']]['comments'][] = $row['comments']; // push new value into subarray
        $ref[$row['userId']]['stars'][] = $row['stars'];       // push new value into subarray
        ++$ref[$row['userId']]['reviews'];                     // increment review count
        $ref[$row['userId']]['starSum'] += $row['stars'];      // add new value to stored sum
        $ref[$row['userId']]['average'] = $ref[$row['userId']]['starSum'] / $ref[$row['userId']]['reviews'];  // calculate new average
    }
}
var_export($result);

这应该为您提供向最终用户显示相关数据所需的每一条数据。

我的样本数据的输出:

array (
  0 => 
  array (
    'id' => '7',
    'name' => 'Alan',
    'comments' => 
    array (
      0 => 'super-ordinary',
    ),
    'stars' => 
    array (
      0 => '3',
    ),
    'reviews' => 1,
    'starSum' => '3',
    'average' => '3',
  ),
  1 => 
  array (
    'id' => '5',
    'name' => 'Bill',
    'comments' => 
    array (
      0 => 'pretty not bad',
      1 => 'what a stinker',
    ),
    'stars' => 
    array (
      0 => '4',
      1 => '1',
    ),
    'reviews' => 2,
    'starSum' => 5,
    'average' => 2.5,
  ),
  2 => 
  array (
    'id' => '1',
    'name' => 'Chad',
    'comments' => 
    array (
      0 => 'super mega wow',
    ),
    'stars' => 
    array (
      0 => '5',
    ),
    'reviews' => 1,
    'starSum' => '5',
    'average' => '5',
  ),
  3 => 
  array (
    'id' => '3',
    'name' => 'Dave',
    'comments' => 
    array (
      0 => 'absolutely ace',
      1 => 'twas very good',
    ),
    'stars' => 
    array (
      0 => '5',
      1 => '4',
    ),
    'reviews' => 2,
    'starSum' => 9,
    'average' => 4.5,
  ),
  4 => 
  array (
    'id' => '2',
    'name' => 'Ned',
    'comments' => 
    array (
      0 => 'a nice quality',
      1 => 'I was very meh',
    ),
    'stars' => 
    array (
      0 => '4',
      1 => '2',
    ),
    'reviews' => 2,
    'starSum' => 6,
    'average' => 3,
  ),
  5 => 
  array (
    'id' => '4',
    'name' => 'Newt',
    'comments' => 
    array (
    ),
    'stars' => 
    array (
    ),
    'reviews' => 0,
    'starSum' => NULL,
    'average' => NULL,
  ),
  6 => 
  array (
    'id' => '6',
    'name' => 'Norton',
    'comments' => 
    array (
    ),
    'stars' => 
    array (
    ),
    'reviews' => 0,
    'starSum' => NULL,
    'average' => NULL,
  ),
)
© www.soinside.com 2019 - 2024. All rights reserved.