如何对数据进行分组以从选择查询中按周显示平均价格

Posted

技术标签:

【中文标题】如何对数据进行分组以从选择查询中按周显示平均价格【英文标题】:How to group data to show average price by weeks from a select query 【发布时间】:2015-10-06 22:57:00 【问题描述】:

我显示从今天起 3 个月的订单。如果今天是 17.07.2015,我显示从 17.04.2015 到 17.07.2015 的数据。我的问题是我必须按周显示这些数据。 3个月有12周。我必须显示所有 12 周的订单平均价格。

现在,在我的查询中,我显示了此期间的所有订单。但我不必显示所有订单的平均价格,必须显示 12 周的 12 个平均价格。该怎么做?

<?php
public function average_price_by_week() 
$date = new DateTime("now");
$date->modify('-3 month');
$current =$date->format('Y-m-d');

$this->db->select('DATE_FORMAT(DATE_SUB(ordersheader.createdDate, INTERVAL DAYOFWEEK(ordersheader.createdDate)-2 DAY), "%Y-%m-%d") AS "interval"',FALSE);
	    	
$this->db->select_avg('unitPrice');
$this->db->from('orderitems');
$this->db->join('ordersheader', 'ordersheader.idOrder=
orderitems.idOrder');
			
$this->db->where('ordersheader.createdDate > ',$current);
			
			
$this->db->order_by('interval');
$this->db->group_by('interval');
$query=$this->db->get();
return $query->result_array();

我的表ordersheader 有结构:

idOrder(主键),idCustomer,createdDate,orderDueDate

我的表orderitems 有结构:

id(主键),idOrder,itemNumber,wrappingType,size,quantity,unitPrice,incomes`

一个 idOrder 可以有多个订单项。

已编辑:我必须在图表中显示此数据。在我的控制器中,我有: 如何从查询而不是数组 $firms 中按周显示平均价格和间隔以从上述数组中获取值?

<?php
 public function column_chart()    
        
      $size = $this->uri->segment(3);
      $interval = $this->uri->segment(4);
      $firms = $this->Receivedorders_model->average_price_by_week($size,$interval);

      $new_result_array=[];
      $average_prices=[];

      foreach($firms as $row)
          
         if(!isset($new_result_array[date('W',strtotime($row['interval']))]))
           $new_result_array[date('W',strtotime($row['interval']))]=[];
           $new_result_array[date('W',strtotime($row['interval']))]['weekly_order_total']=0;
           $new_result_array[date('W',strtotime($row['interval']))]['orders']=[];
         
        
         $new_result_array[date('W',strtotime($row['interval']))]['weekly_order_total']+=$row['unitPrice'];
         $new_result_array[date('W',strtotime($row['interval']))]['orders'][]=$row;
      

      print_r($new_result_array);

      foreach($new_result_array as $week=>$orders)
         $average_prices[$week]=$orders['weekly_order_total']/count($orders['orders']);
      

      print_r($average_prices);



/* How to show average price by week and interval from query in the following array -instead of $firms to take values from the above array  */
     
      $p = array();
      foreach ($firms as $key => $firm) 
        $p[$key] = array('c' => array(array(
          'v' =>  $firm['interval'],  
        ),
        
     
        array(
          'v' =>  round($firm['unitPrice'],2), 
        )));
      
      echo json_encode(array(
      'cols' => array(
          array('id' => 'name',  'label' => lang("customer"),  'type' => 'string'),
          array('id' => 'incomes', 'label' => lang("chart_average_price"),  'type' => 'number'),

        ),
        'rows' => $p

      ));
      
    

【问题讨论】:

请张贴您的表格结构 查看此按周分组:***.com/questions/1736010/… 【参考方案1】:

要在 PHP 中完成整个过程,请更改您的选择并删除 select_avg 并正常选择 unitPrice

$new_result_array=[];
$average_prices=[];

foreach($result_array as $row)
     //Initialize the index's if they dont exist
   if(!isset($new_result_array[date('W',strtotime($row['createdDate']))])
     $new_result_array[date('W',strtotime($row['createdDate'])]=[];
     $new_result_array[date('W',strtotime($row['createdDate'])]['weekly_order_total']=0;
     $new_result_array[date('W',strtotime($row['createdDate'])]['orders']=[];
   
   //Edited to wrap $row['createdDate'] in strtotime() as all dates are returning week 1 
   $new_result_array[date('W',strtotime($row['createdDate']))]['weekly_order_total']+=$row['unitPrice'];
   $new_result_array[date('W',strtotime($row['createdDate']))]['orders'][]=$row;


print_r($new_result_array);

foreach($new_result_array as $week=>$orders)
   $average_prices[$week]=$orders['weekly_order_total']/count($orders['orders']);


print_r($average_prices);

W 作为日期格式会为您提供周数(即 1-52)。如果您需要显示每个周期间的开始和结束日期,则需要解析该数字。有关更多信息,请参阅此问题(可能还有其他问题)

PHP get start and end date of a week by weeknumber

【讨论】:

没有注意子数组分配。它将创建一个按周数在顶层索引的子数组。进一步的工作是计算每个子数组中的项目并计算平均值,但是一旦所有数据都正确分组,这应该是微不足道的。本着完整性的精神,我已经更新了我的答案 我尝试使用此代码,但它给了我错误:遇到格式不正确的数值,未定义索引:weekly_order_total 代码为:$new_result_array=[]; $average_prices=[]; foreach($query->result_array() as $row) $new_result_array[date('W',$row['interval'])]['weekly_order_total']+=$row['unitPrice']; $new_result_array[date('W',$row['interval'])]['orders'][]=$row; foreach($new_result_array as $week=>$orders) $average_prices[$week]=$orders['weekly_order_total']/count($orders['orders']); 在评论中发帖没有多大帮助,因为我无法关注它。 print_r($new_result_array); 输出什么?检查数组,你会发现由于某种原因你没有应该在的数字 我会更新我的问题,所以你可以看到它是正确的。 急需看到print_r($new_result_array);的输出【参考方案2】:

不是一个可移植的解决方案(它使用 mysql 函数;其他 RDBM 具有类似的功能,但名称不同),但您可以WEEKOFYEAR() 对数据进行分组。唯一需要注意的是,如果你在一月份,你会得到例如第 48 周、第 49 周、第 50 周、第 51 周、第 52 周、第 1 周、第 2 周、第 3 周,您需要像这样对它们进行排序(即 52 在 1 之前)。

所以你可以提取

MIN(ordersheader.createdDate) AS firstOrderDate,
WEEKOFYEAR(ordersheader.createdDate) AS weekNumber,

然后按weekNumber 分组,但按firstOrderDate 排序(不显示)。

另一个问题可能是如果您在间隔中缺少数据。

也许更高级的方法是:

    提取日平均价格。然后,您将获得 0 到 ~91 个项目的数据点(如果您在此期间没有订单,则为 0;您必须考虑这种可能性)。 使用一些扩展方法(B 样条 [易于观察]、多项式 [有风险]、线性平均 [可辩护])获取您没有拥有的日子的数据;这将在 PHP 中完成 在 PHP 中重新分组数据,从 90 天到 12 周。 显示 12 个数据点。

数据分组

您可以在查询中添加缺失的数据,但这很棘手。假设您有一个像

这样的结果数组,那么 PHP 的一种更容易理解的方法是
$results = array(
    0 => array(
        'createdDate'   => '2015-07-17',
        'value'         => 2500, // This is the DAY AVERAGE for that day
        ...
    ),

然后你可以做类似的事情,

$weeks = array();
foreach ($results as $row) 
    $weekNumber = date('W', $row['createdDate']);
    if (array_key_exists($weekNumber, $weeks)) 
        $week = $weeks[$weekNumber];
     else 
        $week = array( 'value' => 0, 'count' => 0 );
    
    $week['count'] ++;
    $week['value'] += $row['value'];

// Now get the average
foreach ($weeks as $n => $week) 
   $weeks[$n]['value'] /= $weeks[$n]['count'];

// Now we have $weeks, with "holes" for periods with no data:
/*
    $weeks = array(
        51 => [ 'value' => 172.371, 'count' => 3 ],
         2 => [ 'value' => 211.952, 'count' => 7 ],
         ...
    );
*/
// To fill holes, we first need to choose how to do that (see above).

注意:在上述方法中存在一个(可能可以接受的)概念错误,我们平均一天的平均值。假设我们有:

Day      Price
17       1000
17       1000
17       1000
18       2000

日平均值为:17 = 1000, 18 = 2000。如果这两天都在同一周内,则 1000 和 2000 的平均值将得出一周平均值 1500。但在那一周我们有四个订单,并且那些的平均值实际上是 1250。

你说“周平均”是有歧义的,因为不清楚是每天的平均价格,还是整个期间所有订单的平均价格。

如果你想要第二种类型的平均值,你需要按周数分组,这是我上面最初的建议。

【讨论】:

是的,如果我使用这个,如果我没有间隔的数据,它不会出现星期。如果我使用第二个选项并选择所有天的平均价格,那么如何在之后按周对它们进行分组?

以上是关于如何对数据进行分组以从选择查询中按周显示平均价格的主要内容,如果未能解决你的问题,请参考以下文章

对查询结果分组

在python中按特定年份对数据进行分组

在嵌套选择查询中按条件分组后加入

如何使用 SQL Server 在此查询中按天对结果进行分组?

在 postgresql 中按月和年对查询结果进行分组

如何计算 SQL Server 中按日期和用户分组的条目之间的平均时间?