当前位置: 首页 > 面试题库 >

复杂的“缺口和离岛”问题

陈斌
2023-03-14
问题内容

我在Postgres DB中有一个这样的表:

person    |     eventdate     |  type 
--------------------------------------
<uuid-1>  |   2016-05-14      |   300
<uuid-3>  |   2016-05-14      |   300
<uuid-1>  |   2016-05-15      |   301
<uuid-1>  |   2016-05-16      |   301
<uuid-1>  |   2016-05-18      |   304
<uuid-1>  |   2016-05-22      |   300
<uuid-2>  |   2016-05-22      |   304
<uuid-2>  |   2016-05-27      |   301
<uuid-1>  |   2016-05-30      |   300
<uuid-1>  |   2016-06-01      |   300
<uuid-2>  |   2016-06-15      |   501
<uuid-2>  |   2016-06-16      |   301
<uuid-4>  |   2016-06-16      |   300
<uuid-5>  |   2016-06-20      |   300
<uuid-1>  |   2016-06-21      |   300
<uuid-2>  |   2016-06-21      |   300
<uuid-2>  |   2016-06-23      |   301
<uuid-2>  |   2016-06-30      |   300
<uuid-3>  |   2016-06-30      |   300
<uuid-4>  |   2016-06-30      |   300

该表包含因缺勤原因(类型)不同而导致雇员缺勤的每一天的非连续日条目。但是,缺勤期可能跨越这几天,并且在以前没有相同类型的5天之内的任何缺勤条目仍被视为相同缺勤“期间”的一部分。

我需要获取每个员工缺勤期间的输出,这些期间的开始和结束日期加上该跨多个日期的期间内的总天数。

由于本报告目的将不同类型的缺勤视为相同,这一事实使情况更加复杂。因此,在上面的示例中,类型300、301、304将被视为相同。

因此,从上面的示例中,以下内容将是我所追求的…

person    |     startdate     |       enddate     |  days   |  type 
--------------------------------------------------------------------
<uuid-1>  |     2016-05-14    |     2016-05-22    |   5     |   300
<uuid-3>  |     2016-05-14    |     2016-04-14    |   1     |   300
<uuid-2>  |     2016-05-22    |     2016-04-27    |   2     |   304
<uuid-1>  |     2016-05-30    |     2016-06-01    |   2     |   300
<uuid-2>  |     2016-06-15    |     2016-06-15    |   1     |   501
<uuid-2>  |     2016-06-16    |     2016-06-16    |   1     |   301
<uuid-4>  |     2016-06-16    |     2016-06-16    |   1     |   300
<uuid-5>  |     2016-06-20    |     2016-06-20    |   1     |   300
<uuid-1>  |     2016-06-21    |     2016-06-21    |   1     |   300
<uuid-2>  |     2016-06-21    |     2016-06-23    |   2     |   300
<uuid-2>  |     2016-06-30    |     2016-06-30    |   1     |   300
<uuid-3>  |     2016-06-30    |     2016-06-30    |   1     |   300
<uuid-4>  |     2016-06-30    |     2016-06-30    |   1     |   300

如何查询此表到此输出?


问题答案:

目前尚不清楚您如何确定type每个期间的费用。我选择了最小数量。

假设此基本表定义为:

CREATE TABLE tbl (person text, eventdate date, type int);

基本上,我建议在两个嵌套的子查询中使用窗口函数来标识同一时期(岛屿)的成员。然后合计:

SELECT person, period
     , min(eventdate) AS startdate
     , max(eventdate) AS enddate
     , count(*)       AS days
     , min(type)      AS type
FROM  (
   SELECT person, eventdate, type
        , count(gap) OVER (PARTITION BY person ORDER BY eventdate) AS period
   FROM  (
      SELECT person, eventdate, type
           , CASE WHEN lag(eventdate) OVER (PARTITION BY person ORDER BY eventdate)
                     > eventdate - 6  -- within 5 days
                  THEN NULL           -- same period
                  ELSE TRUE           -- next period
             END AS gap
      FROM   tbl
      ) sub
   ) sub
GROUP  BY person, period
ORDER  BY person, period;

结果(基于您的示例数据):

  person  | period | startdate  |  enddate   | days | type
----------+--------+------------+------------+------+------
 <uuid-1> |      1 | 2016-05-14 | 2016-05-22 |    5 |  300
 <uuid-1> |      2 | 2016-05-30 | 2016-06-01 |    2 |  300
 <uuid-1> |      3 | 2016-06-21 | 2016-06-21 |    1 |  300
 <uuid-2> |      1 | 2016-05-22 | 2016-05-27 |    2 |  301
 <uuid-2> |      2 | 2016-06-15 | 2016-06-23 |    4 |  300
 <uuid-2> |      3 | 2016-06-30 | 2016-06-30 |    1 |  300
 <uuid-3> |      1 | 2016-05-14 | 2016-05-14 |    1 |  300
 <uuid-3> |      2 | 2016-06-30 | 2016-06-30 |    1 |  300
 <uuid-4> |      1 | 2016-06-16 | 2016-06-16 |    1 |  300
 <uuid-4> |      2 | 2016-06-30 | 2016-06-30 |    1 |  300
 <uuid-5> |      1 | 2016-06-20 | 2016-06-20 |    1 |  300

如果可以使用不同的类型多次输入同一个人的同一天,并且您只想计算 不同的 天数,请设置为:count(DISTINCT eventdate) AS days

相关,并有详细说明:

  • 选择最长的连续序列
  • 当组归属取决于前一行时,如何在postgresql中标记组?

顺便说一句,eventdate - 6适用于数据类型date,但不适用于timestamp

  • 如何使用PostgreSQL确定上个月的最后一天?


 类似资料:
  • 如果你曾经了解过依赖注入,那么你可能见过 “控制反转”(Inversion of Control) 或者 “依赖反转准则”(Dependency Inversion Principle)这种说法。这些是依赖注入能解决的更复杂的问题。 控制反转 顾名思义,一个系统通过组织控制和对象的完全分离来实现”控制反转”。对于依赖注入,这就意味着通过在系统的其他地方控制和实例化依赖对象,从而实现了解耦。 一些

  • 我试图通过以下当前线程创建我自己的Lombok转换-为Lombok创建自定义注释 我已经通过maven导入了lombok,但仍然无法解决很多依赖项,例如:等 马文: 你知道为什么吗?

  • 我是一个初学者在Laravel,我已经安装Laravel Excel包在我的项目成功.但是,有一个问题出现的包,当我运行它显示这个错误: 加载具有包信息的composer存储库更新依赖项在锁文件中无需修改从锁文件安装依赖项(包括需要开发)包操作:2次安装,0次更新,0次删除 安装Markbaker/复杂(2.0.0):提取存档 安装ezyoung/html净化器(v4.13.0):提取存档生成优化

  • 问题内容: 在Python中,您可以得到两个集合的交集: 有人知道这种相交()算法的复杂性吗? 编辑: 此外,有人知道Python集背后的数据结构是什么吗? 问题答案: 答案似乎是一个搜索引擎查询。您也可以使用此直接链接到python.org的“时间复杂性”页面。快速总结: 编辑:正如雷蒙德在下面指出的那样,“最坏情况”的情况不太可能发生。我最初将其包括在内是为了彻底,我将其留给下面的讨论提供背景

  • 主要内容:时间复杂度,空间复杂度《 算法是什么》一节提到,解决一个问题的算法可能有多种,这种情况下,我们就必须对这些算法进行取舍,从中挑选出一个“最好”的。 算法本身是不分“好坏”的,所谓“最好”的算法,指的是最适合当前场景的算法。挑选算法时,主要考虑以下两方面因素: 执行效率:根据算法所编写的程序,执行时间越短,执行效率就越高; 占用的内存空间:不同算法编写出的程序,运行时占用的内存空间也不相同。如果实际场景中仅能使用少量的内

  • 本文向大家介绍复杂的javascript窗口分帧解析,包括了复杂的javascript窗口分帧解析的使用技巧和注意事项,需要的朋友参考一下 什么是窗口分帧?       窗口分帧就是把一个浏览器文档窗口分隔成多个窗口,每个窗口都可以显示一个独立的网页文件,每个帧(即页面)都有自己的url。 帧窗口该如何创建?   帧通常是由<frameset>和<frame>标记创建的。但在HTML 4中,<if