按月计算只有两个日期字段 - IN和OUT

时间:2013-12-18 22:47:25

标签: mysql sql

未能找到此特定问题的答案。需要在不同产品上按月分组的库存总数。源数据具有日期字段,一个用于IN,一个用于OUT。特定月份的总计数将包括在特定月份之前具有IN日期的所有行的总和,只要该出日期为空或特定月份之后的日期。

显然,我可以通过使用WHERE子句编写count(distinct productID)查询来获取任何给定月份的计数,该子句声明IN Date在我感兴趣的月份之前(IE 2012年9月)和Out Date为null或在9/2012之后:

Where ((in_date <= '2012-09-30') AND (out_date >= '2012-09-01' or out_date is null))  

如果产品在9月份的某一天甚至是库存的一部分,我希望它能算出9月12日以后的日期。以下示例数据。而不是查询特定的月份,我该怎么做呢:

原始数据 - 每一行都是单独的项目

InDate        OutDate        ProductAttr   ProductID

2008-04-05    NULL           Blue          101
2008-06-04    NULL           Red           125
2008-01-01    2012-06-01     Blue          134
2008-12-10    2012-10-09     Red           129
2009-10-15    2012-11-01     Blue          153
2012-10-01    2013-06-01     Red           149

进入这个?:

Date          ProductAttr    Count
2008-04       Blue           503
2008-04       Red            1002
2008-05       Blue           94
2008-05       Red            3004
2008-06       Blue           2000
2008-06       Red            322

通过分组,我可以将原始数据转换为按月分组的格式:

InDate       OutDate      Value    Count

2008-05      2012-05      Blue     119
2008-05      2008-06      Red      333
2008-05      2012-10      Blue     4
2008-05      NULL         Red      17488
2008-06      2012-11      Blue     711
2008-06      2013-02      Red      34

如果你想知道截至2012年10月有多少产品是'IN',你可以计算所有行的计数,除了2. Group on Value以保持蓝色和红色分开。因为OutDate在2012年10月之前排除了第2行。

提前感谢。

编辑:

Gordon Linoff的解决方案就像我需要它一样。我现在唯一的问题是查询的大小和效率,因为我遗漏的部分是产品属性实际上位于不同的表中,然后是IN / OUT日期,我还需要加入第三个表限制某种类型的产品(例如ForSale)。我尝试了两种不同的方法,它们都可以工作并返回相同的数据,但这两种方法都需要很长时间才能自动生成此报告:

select months.mon, count(distinct d.productID), d.ProductAttr
from (select '2008-10' as mon union all
  select '2008-11' union all
  select '2008-12' union all
  select '2009-01'
 ) months left outer join
 t
 on months.mon >= date_format(t.Indate, '%Y-%m') and 
    (months.mon <= date_format(t.OutDate, '%Y-%m') or t.OutDate is NULL)

join x on x.product_id = t.product_id and x.type = 'ForSale'
join d on d.product_id = x.product_id and d.type = 'Attribute'

group by months.mon, d.ProductAttr;

在没有最后两个连接的情况下,通过添加产品属性的子查询和where / exclusion进行了上述尝试 - 这似乎运行相同或稍慢:

select months.mon, count(distinct t.productID), (select ProductAttr from d where productid = t.productID and type = 'attribute' limit 1)
from (select '2008-10' as mon union all
  select '2008-11' union all
  select '2008-12' union all
  select '2009-01'
 ) months left outer join
 t
 on months.mon >= date_format(t.Indate, '%Y-%m') and 
    (months.mon <= date_format(t.OutDate, '%Y-%m') or t.OutDate is NULL)

WHERE exists (select 1 from x where x.productid = t.productID and x.type = 'ForSale')

group by months.mon, d.ProductAttr;

使用我需要依赖3个源表的额外数据来提高效率的任何想法(1仅用于排除)。提前谢谢。

1 个答案:

答案 0 :(得分:0)

您可以通过生成所需月份的列表来完成此操作。最简单的方法是在MySQL中手动执行此操作(尽管在Excel中生成代码可以使这更容易)。

然后使用左连接和聚合来获取所需的信息:

select months.mon, t.ProductAttr, count(distinct t.productID)
from (select '2008-10' as mon union all
      select '2008-11' union all
      select '2008-12' union all
      select '2009-01'
     ) months left outer join
     t
     on months.mon >= date_format(t.Indate, '%Y-%m') and 
        (months.mon <= date_format(t.OutDate, '%Y-%m) or t.OutDate is NULL)
group by t months.mon, t.ProductAttr;

此版本将所有比较作为字符串进行。您正在以“月”的粒度工作,格式YYYY-MM在比较方面做得很好。

编辑:

您确实需要在输出中每个月都需要。如果您每个月都有产品,那么您可以这样做:

select months.mon, t.ProductAttr, count(distinct t.productID)
from (select distinct date_format(t.InDate, '%Y-%m') as mon
      from t
     ) months left outer join
     t
     on months.mon >= date_format(t.InDate, '%Y-%m') and
        (months.mon <= date_format(t.OutDate, '%Y-%m) or t.OutDate is NULL)
group by t months.mon, t.ProductAttr;

这可以从数据中抽出几个月。