如何對數據進行分組,從select查詢中按周顯示平均價格

[英]How to group data to show average price by weeks from a select query


I show orders for a period 3 months from today. If today is 17.07.2015, I show data from 17.04.2015 to 17.07.2015. My problem is that I have to show this data by weeks. In 3 months there are 12 weeks. I have to show average prices of orders for all 12 weeks.

從今天開始,我將展示3個月的訂單。如果今天是17.07.2015,我展示的數據是從17.04.2015到17.07.2015。我的問題是我必須按周顯示這些數據。3個月有12周。我必須顯示所有12周內訂單的平均價格。

Now, in my query, I show all orders which is in this period. But I don't have to show average_prices for all orders, have to show 12 average prices for the 12 weeks. How to do that?

現在,在我的查詢中,我顯示了這段時間內的所有訂單。但我不需要顯示所有訂單的平均價格,必須顯示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();

My table ordersheader has structure:

我的訂貨方有如下結構:

idOrder(Primary key),idCustomer,createdDate,orderDueDate

idOrder(主鍵),idCustomer createdDate orderDueDate

My table orderitems has structure:

我的表orderitems具有結構:

id(Primary key),idOrder,itemNumber,wrappingType,size,quantity,unitPrice,incomes`

id(主鍵),idOrder itemNumber wrappingType,大小,數量,unitPrice,收入

One idOrder can have many orderitems.

一個idOrder可以有多個orderitems。

Edited: I have to show this data in a chart. In my controller I have: How to show average price by week and interval from query instead of the array $firms to take values from the above arrays?

編輯:我必須在圖表中顯示這些數據。在我的控制器中,我有:如何按周和查詢間隔顯示平均價格,而不是用數組$firm從上面的數組中獲取值?

<?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

      ));
      
    }

2 个解决方案

#1


3  

To do the whole process in PHP change your select and remove the select_avg and do a normal select of unitPrice.

要在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 as a date format will give you the number of the weeek (ie 1-52). If you need to show the start and end date of each weekly period you will need to parse that number. See this question (and probably others) for more info

W作為日期格式將給出weeek的編號(即1-52)。如果需要顯示每個星期周期的開始和結束日期,則需要解析該數字。更多信息請參見這個問題(可能還有其他問題)

PHP get start and end date of a week by weeknumber

PHP通過weeknumber獲得一周的開始和結束日期

#2


0  

Not a portable solution (it uses a MySQL function; other RDBMs have similar features but differently named), but you can group the data by WEEKOFYEAR(). The only caveat is that this way if you're in January, you will get e.g. weeks #48, #49, #50, #51, #52, #1, #2, #3 and you will need to sort them just like that (i.e. 52 comes before 1).

不是可移植的解決方案(它使用MySQL函數;其他RDBMs具有類似的特性,但名稱不同),但是可以按周/年()對數據進行分組。唯一要注意的是,如果你是在一月份,你會得到例如:第48周,第49周,第50周,第51周,第52周,第1周,第2周,第3周,你需要像這樣對它們進行排序(例如,第52周在第1周之前)。

So you can extract

所以你可以提取

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

and then group by weekNumber but order by firstOrderDate (without displaying it).

然后按weekNumber組,按firstOrderDate(不顯示)排序。

Another problem might be if you have missing data in the interval.

另一個問題可能是如果在間隔中丟失了數據。

Perhaps a more high-level approach would be:

也許更高級別的辦法是:

  1. Extract day average prices. You then get from 0 to ~91 items worth of data points (0 if you have no orders in the period; you have to consider the possibility).
  2. 提取一天平均價格。然后,從0到~91項的數據點(如果在此期間沒有訂單,則為0);你必須考慮到這種可能性。
  3. Use some extending method (B-splines [easy on the eyes], polynomial [risky], linear average [defensible]) to get data for the days you do not have; this to be done in PHP
  4. 使用一些擴展方法(b樣條[容易在眼睛上],多項式[危險],線性平均[可防御])獲取數據,在你沒有的日子;這在PHP中可以實現
  5. Re-group the data in PHP, from 90 days to 12 weeks.
  6. 用PHP重新分組數據,從90天到12周。
  7. Display the 12 data points.
  8. 顯示12個數據點。

Grouping the data

You can add missing data in the query but it's tricky. A more approachable way from PHP would be this, supposing that you have a result array like

您可以在查詢中添加缺失的數據,但這很棘手。PHP中更容易接近的方法是這樣的,假設您有一個結果數組

$results = array(
    0 => array(
        'createdDate'   => '2015-07-17',
        'value'         => 2500, // This is the DAY AVERAGE for that day
        ...
    ),

Then you can do something like,

然后你可以做一些類似的事情,

$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).

Note: there is a (possibly acceptable) conceptual error in the above approach, where we average the day averages. Suppose we have:

注意:在上面的方法中有一個(可能可以接受的)概念上的錯誤,即我們對日平均值進行平均。假設我們有:

Day      Price
17       1000
17       1000
17       1000
18       2000

The day averages will be: 17 = 1000, 18 = 2000. If both days are in the same week, the average of 1000 and 2000 will give a week average of 1500. Yet in that week we had four orders, and the average of those would actually be 1250.

一天的平均數是:17 = 1000,18 = 2000。如果這兩個日子都在同一個星期,1000和2000的平均值會給出一個星期的平均值1500。但在那一周,我們有4個訂單,這些訂單的平均值實際上是1250。

There is an ambiguity when you say "week average", because it is not clear whether it is the average of the prices of each day, or the average of the prices of all orders in the whole period.

當你說“周均線”時,會有一種歧義,因為不清楚它是每天的平均價格,還是整個周期內所有訂單的平均價格。

If you want the second type of average, you need to group by week number, which was my initial proposal above.

如果你想要第二種平均值,你需要按周數進行分組,這是我上面最初的建議。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2015/07/17/725683f40bd5ef801839f1cc5e594527.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com