2017-09-07 104 views
0

我试图在mySQL中完成某些工作,由于缺乏“滞后”功能以及因为所有关于日期差异的示例,因此很难实现,因为在所有这些例子总是有一个ID到一个日期。在这里,我试图在一个ID内做日期差异,并且当日期差异超过60时,然后返回1的指示符,否则为0.在一个ID内减去多个日期

不知道最好的方法是怎么去做这件事。是否将row_number()与日期结合使用?这个障碍是在多个ID内完成的,因为我读过的很多东西都没有涵盖。任何方向都会有帮助。 谢谢!

ID | Service Date | Date Difference | Indicator 
1 | 1/22/2016  | 0    | 1 
1 | 3/26/2016  | 64    | 1 
1 | 5/25/2016  | 60    | 0 
1 | 9/15/2016  | 113    | 1 
2 | 8/1/2016  | 0    | 1 
3 | 1/26/2016  | 0    | 1 
3 | 3/9/2016  | 43    | 0 
3 | 4/30/2016  | 52    | 0 
4 | 8/9/2016  | 0    | 1 
5 | 11/19/2016  | 0    | 1 
6 | 10/14/2016  | 0    | 1 
7 | 1/31/2016  | 0    | 1 
7 | 8/11/2016  | 193    | 1 
+0

不能与MySQL使用行号无论是。 –

+0

使用用户变量保存上一行的日期,然后使用'DATEDIFF(service_date,@previous_date)'来获得差异。 – Barmar

+0

您还需要一个用于以前的ID的变量。当ID改变时,你重新开始。 – Barmar

回答

1
create view id_and_date as 
select id, service_date from your table; 

create view id_and_date_and_prior as 
select 
a.id, a.service_date, 
coalesce(
    (select max(b.service_date) from id_and_date b 
    where b.id = a.id and b.service_date < a.service_date), 
a.service_date) 
as prior_date 
from id_and_date a 

select a.id, a.service_date, a.prior_date 
date_diff(a.service_date, a.prior_date) as diff, 
case when date_diff(a.service_date, a.prior_date) > 60 
    then 1 else 0 end 
as indicator 
from id_and_date_and_prior a 
+0

该OP想要一个滚动的差异,而不是从第一个差异。 – fyrye

+0

请记住,如果我简化你的答案? – fyrye

+0

如果您添加自己的答案(可选地指出简化),它会让我更不迷惑,并教育我更多!如果您想减少视图的数量,我故意将它们分开,以便于阅读/理解。 – tpdi

1

可以使用变量,但是这是非常棘手。对于这个可靠地工作,所有的变量都需要在一个单一的表达被分配:

select t.*, datediff(prev_date, date) as diff, 
     (case when datediff(prev_date, date) < 60 then 0 else 1 end) as indicator 
from (select t.*, 
      (case when @id = id 
        then (case when (@prev := @d) = NULL then 'never' -- intentional 
           when (@d := date) = NULL then 'never' -- intentional 
           else @prev 
         end) 
        when (@d := date) = NULL then 'never' -- intentional 
        else NULL 
       end) as prev_date 
     from t cross join 
      (select @id := -1, @d := '') params 
     order by id, date 
    ) t 
1

发布,以简化和纠正功能由@tpdi提供的接听电话。请接受/ upvote他们的答案,因为这是非常复制它。

的变化:

  • date_diff到DATEDIFF
  • 除去创建视图呼叫赞成t子查询的
  • 分配变量涉及diff值的0初始值
  • 指示符0 diff来1
  • 当案件有利于IF时更换
SELECT 
c.id, 
c.service_date, 
@diff := DATEDIFF(c.service_date, c.prior_date) AS diff, 
IF(@diff = 0 || @diff > 60, 1, 0) AS indicator 
FROM (
    SELECT 
    a.id, 
    a.service_date, 
    COALESCE(
     (SELECT MAX(b.service_date) 
     FROM t AS b 
     WHERE b.id = a.id 
     AND b.service_date < a.service_date), 
     a.service_date 
    ) AS prior_date 
    FROM t AS a 
) AS c; 

会导致:

| id | service_date | diff | indicator | 
| 1 | 2016-01-22 | 0 | 1   | 
| 1 | 2016-03-26 | 64 | 1   | 
| 1 | 2016-05-25 | 60 | 0   | 
| 1 | 2016-09-15 | 113 | 1   | 
| 2 | 2016-08-01 | 0 | 1   | 
| 3 | 2016-01-26 | 0 | 1   | 
| 3 | 2016-03-09 | 43 | 0   | 
| 3 | 2016-04-30 | 52 | 0   | 
| 4 | 2016-08-09 | 0 | 1   | 
| 5 | 2016-11-19 | 0 | 1   | 
| 6 | 2016-10-14 | 0 | 1   | 
| 7 | 2016-01-31 | 0 | 1   | 
| 7 | 2016-08-11 | 193 | 1   | 
+1

很好地完成。害怕我最近没有做过Mysql,所以select中的变量对我来说是新的!谢谢! – tpdi

+0

@tpdi谢谢,我喜欢你使用'MAX'和'COALESCE',我写的答案是以类似的方式使用'JOIN',但是决定你是一个更好的方法。 – fyrye