【问题标题】:subtract multiple dates within one id在一个 id 中减去多个日期
【发布时间】:2017-09-07 22:55:57
【问题描述】:

我正在尝试在 mySQL 中完成一些事情,这很困难,因为缺少“滞后”功能以及我读过的所有关于日期差异的示例,因为在所有这些示例中,总是有一个 ID一次约会。在这里,我试图在一个 ID 内做日期差异,当日期差异超过 60 时,返回一个指示符 1,否则返回 0。

不确定解决此问题的最佳方法是什么。是否将 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

【问题讨论】:

  • mysql也不能使用行号。
  • 使用用户变量来保存上一行的日期,然后使用DATEDIFF(service_date, @previous_date) 得到差异。
  • 您还需要一个用于之前 ID 的变量。当 ID 发生变化时,您重新开始。
  • 像这样让行相互依赖有点难闻。是否还有其他分类依据,例如用户ID?也许您可以尝试将引用/外键(在自己上)存储到该行的先前服务。

标签: mysql sql date datediff


【解决方案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

【讨论】:

    【解决方案2】:
    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
    

    【讨论】:

    • OP 想要滚动差异,而不是与第一个差异。
    • 如果您添加自己的答案(可选地指出简化),它将减少我的困惑,并教育我更多!如果您想减少查看次数,我特意将它们分开,以便于阅读/理解。
    【解决方案3】:

    发布以简化和更正@tpdi 提供的答案中的函数调用。请接受/赞成他们的回答,因为这几乎是从它那里复制而来的。

    变化:

    • date_diff 到 DATEDIFF
    • 删除了创建视图调用以支持t 的子查询
    • 将变量分配给差异值
    • 初始值为 0 的指示符为 0 与 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         |
    

    【讨论】:

    • 做得很好。怕是最近没做Mysql,所以select里面的变量对我来说是新的!谢谢!
    • @tpdi 谢谢,我喜欢你使用MAXCOALESCE,我写的答案是以类似的方式使用JOIN,但认为你的方法更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-12
    相关资源
    最近更新 更多