如何在同一组数据的日期中找到差距-MySQL

时间:2018-06-23 10:55:01

标签: mysql gaps-and-islands

我有一个日期列表,这些日期之间存在间隙以执行促销。

id       promotion_name  period      value
8495115  Cash_Discount1  2016-11-01  10.00
8495116  Cash_Discount1  2016-12-01  20.00
8491724  Cash_Discount1  2017-01-01  10.00
8479109  Cash_Discount1  2017-02-01  20.00
8459125  Cash_Discount1  2017-03-01  40.00
8491649  Cash_Discount1  2017-06-01  30.00
8491648  Cash_Discount1  2017-07-01  50.00
8491647  Cash_Discount1  2017-08-01  70.00
8491646  Cash_Discount1  2017-09-01  80.00

上表中的时间段表示促销活动的开始日期,为期一个月。 因此,第一行表示现金折扣从2016年11月11日至 2016年11月30日。

我需要以下所述格式的相同数据。

promotion_name start_date  end_date    value
Cash_Discount1  2016-11-01  2017-03-31  100.00
Cash_Discount1  2017-06-01  2017-09-30  230.00

每当有间隙时,它都必须显示为单独的行。有人可以帮我吗,因为任何数量的自我加入都没有给我结果。

我尝试将其用于初学者,但我离结果还差得远。

SELECT p.id
     , p.promotion_name
     , p.period AS start_date
     , q.period AS end_date
     , p.value AS spend
  FROM table p 
  LEFT 
  JOIN table q 
    ON p.id = q.id 
   AND p.promotion_name = q.promotion_name
   AND p.period = DATE_SUB(q.period,INTERVAL 1 MONTH)

我处于一种不知道要搜索什么的情况下。

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

select
  ts.promotion_name,
  min(t.period) as date_start,
  max(t.period) as date_end,
  sum(t.value)  as spend
from mytable ts
left join mytable t1
  on  t1.promotion_name = ts.promotion_name
  and t1.period = ts.period - interval 1 month
join mytable t
  on  t.promotion_name = ts.promotion_name
  and t.period >= ts.period
  and t.period <= (
    select min(t2.period)
    from mytable t2
    left join mytable t3
      on  t3.promotion_name = t2.promotion_name
      and t3.period = t2.period + interval 1 month
    where t2.promotion_name = ts.promotion_name
      and t2.period >= ts.period
      and t3.period is null
  )
where ts.promotion_name = 'Cash_Discount1'
  and t1.period is null
group by ts.id
order by date_start

演示:https://www.db-fiddle.com/f/7Xx5bSQmRUGzUCLyB4rKBf/1

该查询的想法是首先找到具有的连续组的第一行

select ts.*
from mytable ts
left join mytable t1
  on  t1.promotion_name = ts.promotion_name
  and t1.period = ts.period - interval 1 month
where ts.promotion_name = 'Cash_Discount1'
  and t1.period is null

演示:https://www.db-fiddle.com/f/fKaNQPkgZqbTfY3Je6Kz4/0

并通过子查询获取组的最后日期

select min(t2.period)
from mytable t2
left join mytable t3
  on  t3.promotion_name = t2.promotion_name
  and t3.period = t2.period + interval 1 month
where t2.promotion_name = ts.promotion_name
  and t2.period >= ts.period
  and t3.period is null

演示:https://www.db-fiddle.com/f/hSNZwjDuL1nf2NzPoms5JG/0

然后您需要另一个具有范围条件的联接

  and t.period >= ts.period    -- start_date
  and t.period <= (<subquery>) -- end_date

并在匹配的行上使用聚合。