Mysql 跨行查找日期范围

Posted

技术标签:

【中文标题】Mysql 跨行查找日期范围【英文标题】:My SQL Finding a span of dates accross rows 【发布时间】:2013-04-25 15:58:34 【问题描述】:

我正在寻求一些帮助,甚至知道从哪里开始。本质上,我们为客户提供了一个表格,其中包含就业开始日期和结束日期。对于年度报告,我们必须计算“持续就业”,即最早开始日期到最后结束日期,只要一个结束日期和下一个开始日期之间不超过 21 天。 这是一个例子

employee | Start Date | End Date
1        | 2012-10-1  | 2012-11-05
1        | 2012-11-08 | 2013-1-25
2        | 2012-10-1  | 2012-11-05
2        | 2012-11-30 | 2013-1-02

在上面,我希望员工 1 从 2012 年 10 月 1 日到 2013 年 1 月 25 日连续受雇 但员工 2 将有 2 条单独的就业线,显示从 2012-10-1 到 2012-11-05 连续就业和从 012-11-30 到 2013-1-02 不同

感谢您的帮助!

【问题讨论】:

【参考方案1】:

理论类似于@mellamokb's answer,但更简洁一些:

SELECT employee, MIN(start) start, end
FROM (
  SELECT   @end:=IF(employee<=>@emp AND @stt<=end+INTERVAL 21 DAY,@end,end) end,
           @stt:=start start,
           @emp:=employee AS employee
  FROM     my_table, (SELECT @emp:=NULL, @stt:=0, @end:=0) init
  ORDER BY employee, start DESC
) t
GROUP BY employee, end

在sqlfiddle 上查看。

【讨论】:

太棒了!感谢您的答复!这将是我第一次在 select 语句中主动使用定义的变量。这个答案是漂亮的代码:-D【参考方案2】:

在一组记录中找到“连续组”的一种方法是使用变量来跟踪每行之间的差异,并开发将连续范围组合在一起的分组。在下面的示例中,我使用三个变量来跟踪用于生成组的足够信息:

@curEmployee - 从上一个记录中跟踪当前员工,并与当前记录上的员工进行比较,以了解我们何时切换到另一个员工,这会自动成为另一个分组 @curEndDate - 跟踪上一条记录的最后结束日期,因此可以将其与当前记录的开始日期进行比较,以查看当前记录是否与上一条记录属于同一“组”——即比如说,它是以前记录的连续就业的一部分 @curGroup - 这是将行分隔为代表连续就业的单独“组”的关键变量。逻辑是,当且仅当以下两个条件为真时,应该认为一行与上一行是连续的:两行具有相同的员工编号,并且上一行的结束日期小于 21 天当前行。 注意:您可能需要验证边缘条件,即是否将正好相隔 20/21/22 天视为连续就业,并调整以下逻辑。

这是计算这些组的示例查询。有几点需要注意:变量赋值的顺序很重要,因为它们在select 列表中是从上到下分配的。我们需要首先分配@curGroup,以便它仍然具有上一个记录中的@curEmployee@curEndDate 的值以供使用。其次,order by 子句非常重要,可以确保我们在比较上一条记录和当前记录时,它们是彼此最接近的两条记录。如果我们以随机顺序查看记录,它们很可能最终都成为单独的组。

select
  e.employee, e.`start date`, e.`end date`
  ,@curGroup :=
    case when employee = @curEmployee
      and @curEndDate + INTERVAL 21 DAY >= e.`start date`
        then @curGroup
        else @curGroup + 1
    end as curGroup
  ,@curEmployee := employee as curEmployee
  ,@curEndDate := e.`end date` as curEndDate
from
  employment e
JOIN (SELECT @curEmployee := 0, @curEndDate := NULL, @curGroup := 0) r
order by e.employee, e.`start date`

示例结果 (DEMO) - 请注意前两行 CURGROUP 是如何保持在 1 的,因为它们彼此相隔 21 天并代表连续就业,而最后两行被标识为单独的组号:

| EMPLOYEE |                      START DATE |                        END DATE | CURGROUP | CUREMPLOYEE |          CURENDDATE |
-------------------------------------------------------------------------------------------------------------------------------
|        1 |  October, 01 2012 00:00:00+0000 | November, 05 2012 00:00:00+0000 |        1 |           1 | 2012-11-05 00:00:00 |
|        1 | November, 08 2012 00:00:00+0000 |  January, 25 2013 00:00:00+0000 |        1 |           1 | 2013-01-25 00:00:00 |
|        2 |  October, 01 2012 00:00:00+0000 | November, 05 2012 00:00:00+0000 |        2 |           2 | 2012-11-05 00:00:00 |
|        2 | November, 30 2012 00:00:00+0000 |  January, 02 2013 00:00:00+0000 |        3 |           2 | 2013-01-02 00:00:00 |

既然我们已经建立了作为连续就业一部分的记录组,我们只需要按这些组编号进行分组,并找到输出的最小和最大日期范围:

select
  employee,
  min(`start date`) as `start date`,
  max(`end date`) as `end date`
from (
    select
      e.employee, e.`start date`, e.`end date`
      ,@curGroup :=
        case when employee = @curEmployee
          and @curEndDate + INTERVAL 21 DAY >= e.`start date`
            then @curGroup
            else @curGroup + 1
        end as curGroup
      ,@curEmployee := employee as curEmployee
      ,@curEndDate := e.`end date` as curEndDate
    from
      employment e
    JOIN (SELECT @curEmployee := 0, @curEndDate := NULL, @curGroup := 0) r
    order by e.employee, e.`start date`
) as T
group by curGroup

示例结果 (DEMO):

| EMPLOYEE |                      START DATE |                        END DATE |
--------------------------------------------------------------------------------
|        1 |  October, 01 2012 00:00:00+0000 |  January, 25 2013 00:00:00+0000 |
|        2 |  October, 01 2012 00:00:00+0000 | November, 05 2012 00:00:00+0000 |
|        2 | November, 30 2012 00:00:00+0000 |  January, 02 2013 00:00:00+0000 |

【讨论】:

以上是关于Mysql 跨行查找日期范围的主要内容,如果未能解决你的问题,请参考以下文章

mysql日期范围查找(两个日期之间的记录)

帮助形成 mysql 查询以查找给定日期范围的免费(可用)场所/资源

生成一个mysql BETWEEN子句以在日期范围内查找

Mysql - 使用多个连接表查找丢失的日期

SQL Server - 跨行汇总日期范围,同时保留间隙

MySQL 根据身份证查找年龄段