Php 如何在每年每个月的结束日期前获取数据?

Php 如何在每年每个月的结束日期前获取数据?,php,mysql,sql,eloquent,Php,Mysql,Sql,Eloquent,这是我表格中的示例数据 id_item | qty | t_in | t_out | created_at 1 5 1 0 2018-07-05 10:41:00 1 5 1 0 2018-08-03 10:41:00 1 5 0 1 2018-08-05 10:41:00 1 5 1 0 2018-09-05 10:41

这是我表格中的示例数据

id_item | qty | t_in | t_out | created_at
 1         5     1       0    2018-07-05 10:41:00
 1         5     1       0    2018-08-03 10:41:00
 1         5     0       1    2018-08-05 10:41:00
 1         5     1       0    2018-09-05 10:41:00
 1         5     1       0    2018-09-20 10:41:00
 1         5     0       1    2018-10-31 10:41:00
我的预期结果将是

id_item | qty | year | month
 1         5    2018   07
 1         5    2018   08
 1         15   2018   09
 1         10   2018   10
我尝试过的方法是有效的,但当我想按月份分组时,效果并不理想

$date = '2018-10-31'
$test = Model::whereDate('created_at','<=',$date)->select(DB::raw('(SUM(CASE T_IN WHEN 1 THEN qty ELSE qty * - 1 END)) as total'))->groupBy('id_item')->get();

从上面的查询中,我只能得到一行记录。我还尝试按月份和年份分组,但由于日期条件导致结果不正确。如何包含多个这是一个滚动求和问题。在较新版本的Mariadb/MySQL中,可以使用带框架的窗口函数来解决此问题。然而

我们可以使用用户定义的变量来解决这个问题。在派生表中,我们首先确定一个月的总数量变化。然后,我们使用此结果集计算月底的最终数量,方法是将上月行的数量与当月行的数量变化相加

我还扩展了查询,以考虑存在多个IDI项值时的情况。

尝试以下原始查询:

SELECT 
  @roll_qty := CASE WHEN @id_itm = dt.id_item 
                    THEN @roll_qty + dt.qty_change 
                    ELSE dt.qty_change  
               END AS qty, 
  @id_itm := dt.id_item AS id_item, 
  dt.year, 
  dt.month 
FROM 
(
 SELECT 
   t.id_item, 
   SUM(t.qty * t.t_in - t.qty * t.t_out) AS qty_change, 
   YEAR(t.created_at) AS `year`, 
   LPAD(MONTH(t.created_at), 2, '0') AS `month`
 FROM your_table AS t 
 GROUP BY t.id_item, `year`, `month`
 ORDER BY t.id_item, `year`, `month` 
) AS dt 
CROSS JOIN (SELECT @roll_qty := 0, 
                   @id_itm := 0
           ) AS user_init_vars;

| id_item | year | month | qty |
| ------- | ---- | ----- | --- |
| 1       | 2018 | 07    | 5   |
| 1       | 2018 | 08    | 5   |
| 1       | 2018 | 09    | 15  |
| 1       | 2018 | 10    | 10  |

如果要使用变量,则需要正确地使用。MySQL不保证SELECT中表达式的求值顺序。因此,变量不应该在一个表达式中赋值,然后在另一个表达式中使用

这会产生复杂的表达式,但也有可能:

select yyyy, mm, total,
       (@t := if(@ym = concat_ws('-', yyyy, mm), @t + total,
                 @ym := concat_ws('-', yyyy, mm), total
                )
       ) as running_total                 
from (select year(created_at) as yyyy, month(created_at) as mm,
             id_item, 
             sum(case T_IN when 1 then qty else - qty end) as total 
      from transactions 
      where created_at < '2018-11-01'
      group by id_item
      order by id_item, min(created_at)
     ) i cross join
     (select @ym := '', @n := 0);

add->groupBy'YEARcreated_at'->groupBy'MONTHcreated_at'检查这个问题您的主键是什么?您可以将总和简化为SUMqty*t\u in-qty*t_out@MadhurBhaiya我只想显示今年和今年12个月的数量。如果使用组,那么它将显示所有不同的月份和年份。我在使用我自己的查询,选择今年每个月的12个结束日,然后将join保留到我的事务表中,结果看起来不错。选择“2018-01-31”作为月日,选择“2018-02-28”作为月日,依此类推。。。然后左键连接到我的事务表并暂时使用@Crazy,如果您可以使用Elounting进行自己的查询,那么就开始吧。在较小的数据集中,性能不会成为问题;一旦您开始遇到性能瓶颈,到那时,您就有望升级您的mariadb版本。在这种情况下,您只需使用窗口函数。此查询将比使用union和left join更有效。但当数据变大时,差异就会变得明显。是的,表格本身已经达到了6位数的记录。我认为演出会很慢。我认为需要找到其他方法来实现这一目标。
SELECT 
  @roll_qty := CASE WHEN @id_itm = dt.id_item 
                    THEN @roll_qty + dt.qty_change 
                    ELSE dt.qty_change  
               END AS qty, 
  @id_itm := dt.id_item AS id_item, 
  dt.year, 
  dt.month 
FROM 
(
 SELECT 
   t.id_item, 
   SUM(t.qty * t.t_in - t.qty * t.t_out) AS qty_change, 
   YEAR(t.created_at) AS `year`, 
   LPAD(MONTH(t.created_at), 2, '0') AS `month`
 FROM your_table AS t 
 GROUP BY t.id_item, `year`, `month`
 ORDER BY t.id_item, `year`, `month` 
) AS dt 
CROSS JOIN (SELECT @roll_qty := 0, 
                   @id_itm := 0
           ) AS user_init_vars;

| id_item | year | month | qty |
| ------- | ---- | ----- | --- |
| 1       | 2018 | 07    | 5   |
| 1       | 2018 | 08    | 5   |
| 1       | 2018 | 09    | 15  |
| 1       | 2018 | 10    | 10  |
select yyyy, mm, total,
       (@t := if(@ym = concat_ws('-', yyyy, mm), @t + total,
                 @ym := concat_ws('-', yyyy, mm), total
                )
       ) as running_total                 
from (select year(created_at) as yyyy, month(created_at) as mm,
             id_item, 
             sum(case T_IN when 1 then qty else - qty end) as total 
      from transactions 
      where created_at < '2018-11-01'
      group by id_item
      order by id_item, min(created_at)
     ) i cross join
     (select @ym := '', @n := 0);