查找序列中缺少的日期

时间:2016-04-25 17:05:50

标签: sql oracle oracle11g

我有ID和DATE的下表

ID   DATE
123   7/1/2015
123   6/1/2015
123   5/1/2015
123   4/1/2015
123   9/1/2014
123   8/1/2014
123   7/1/2014
123   6/1/2014
456   11/1/2014
456   10/1/2014
456   9/1/2014
456   8/1/2014
456   5/1/2014
456   4/1/2014
456   3/1/2014
789   9/1/2014
789   8/1/2014
789   7/1/2014
789   6/1/2014
789   5/1/2014
789   4/1/2014
789   3/1/2014

在此表中,我有三个客户ID,123,456,789和日期列,显示他们工作的月份。

我想知道哪些客户的工作存在差距。 我们的客户工作记录每月保存...所以,日期是每月.. 每个客户都有不同的开始和结束日期。

预期结果:

ID     First_Absent_date

123    10/01/2014
456    06/01/2014

3 个答案:

答案 0 :(得分:1)

要获得带有间隙的ID的简单列表,没有进一步的详细信息,您需要单独查看每个ID,并且如@mikey建议您可以计算月数并查看第一个和最后一个日期以查看如果跨越多少个月。

如果您的表中有一个名为month的列(由于date不允许,除非它是带引号的标识符),您可以从以下开始:

select id, count(month), min(month), max(month),
  months_between(max(month), min(month)) + 1 as diff
from your_table
group by id
order by id;

        ID COUNT(MONTH) MIN(MONTH) MAX(MONTH)       DIFF
---------- ------------ ---------- ---------- ----------
       123            8 01-JUN-14  01-JUL-15          14
       456            7 01-MAR-14  01-NOV-14           9
       789            7 01-MAR-14  01-SEP-14           7

然后在having子句中将计数与月份跨度进行比较:

select id
from your_table
group by id
having count(month) != months_between(max(month), min(month)) + 1
order by id;

        ID
----------
       123
       456

如果您实际上可以在一个月内为ID创建多条记录,并且/或记录的日期可能不是月初,那么您可以做更多工作来规范化日期:

select id,
  count(distinct trunc(month, 'MM')),
  min(trunc(month, 'MM')),
  max(trunc(month, 'MM')),
  months_between(max(trunc(month, 'MM')), min(trunc(month, 'MM'))) + 1 as diff
from your_table
group by id
order by id;

select id
from your_table
group by id
having count(distinct trunc(month, 'MM')) !=
  months_between(max(trunc(month, 'MM')), min(trunc(month, 'MM'))) + 1
order by id;

答案 1 :(得分:0)

您可以使用Lag()函数查看是否已跳过特定日期的记录.Lag()基本上有助于将当前行中的数据与上一行进行比较。因此,如果我们按日期订购,我们可以轻松地比较并找到任何差距。

select * from 
   (
    select ID,DATE_, case when DATE_DIFF>1 then 1  else 0 end comparison from
        (
          select ID, DATE_ ,DATE_-LAG(DATE_, 1) OVER (PARTITION BY ID ORDER BY DATE_)  date_diff from trial
        )
    )
    where comparison=1 order by ID,DATE_;

按ID对所有条目进行分组,然后按日期排列记录。如果客户总是在场,那么他的约会就不会有差距。所以日期差异大于1的人都有差距。你可以根据你的要求调整它。

编辑:刚刚观察到您以mm / dd / yyyy格式存储数据,当我仔细观察上述答案时。您只存储每个月的第一个日期。因此,上述查询可以调整为:

select * from 
   (
    select ID,DATE_,PREV_DATE,last_day(PREV_DATE)+1 ABSENT_DATE, case when DATE_DIFF>31 then 1  else 0 end comparison from
        (
          select ID, DATE_ ,LAG(DATE_,1)  OVER (PARTITION BY ID ORDER BY DATE_)  PREV_DATE,DATE_-LAG(DATE_, 1) OVER (PARTITION BY ID ORDER BY DATE_)  date_diff from trial
        )
    )
    where comparison=1 order by ID,DATE_;

答案 2 :(得分:0)

Oracle安装程序

CREATE TABLE your_table ( ID, "DATE" ) AS
SELECT 123, DATE '2015-07-01' FROM DUAL UNION ALL
SELECT 123, DATE '2015-06-01' FROM DUAL UNION ALL
SELECT 123, DATE '2015-05-01' FROM DUAL UNION ALL
SELECT 123, DATE '2015-04-01' FROM DUAL UNION ALL
SELECT 123, DATE '2014-09-01' FROM DUAL UNION ALL
SELECT 123, DATE '2014-08-01' FROM DUAL UNION ALL
SELECT 123, DATE '2014-07-01' FROM DUAL UNION ALL
SELECT 123, DATE '2014-06-01' FROM DUAL UNION ALL
SELECT 456, DATE '2014-11-01' FROM DUAL UNION ALL
SELECT 456, DATE '2014-10-01' FROM DUAL UNION ALL
SELECT 456, DATE '2014-09-01' FROM DUAL UNION ALL
SELECT 456, DATE '2014-08-01' FROM DUAL UNION ALL
SELECT 456, DATE '2014-05-01' FROM DUAL UNION ALL
SELECT 456, DATE '2014-04-01' FROM DUAL UNION ALL
SELECT 456, DATE '2014-03-01' FROM DUAL UNION ALL
SELECT 789, DATE '2014-09-01' FROM DUAL UNION ALL
SELECT 789, DATE '2014-08-01' FROM DUAL UNION ALL
SELECT 789, DATE '2014-07-01' FROM DUAL UNION ALL
SELECT 789, DATE '2014-06-01' FROM DUAL UNION ALL
SELECT 789, DATE '2014-05-01' FROM DUAL UNION ALL
SELECT 789, DATE '2014-04-01' FROM DUAL UNION ALL
SELECT 789, DATE '2014-03-01' FROM DUAL;

<强>查询

SELECT ID,
       MIN( missing_date )
FROM   (
  SELECT ID,
         CASE WHEN LEAD( "DATE" ) OVER ( PARTITION BY ID ORDER BY "DATE" )
                     = ADD_MONTHS( "DATE", 1 ) THEN NULL
              WHEN LEAD( "DATE" ) OVER ( PARTITION BY ID ORDER BY "DATE" )
                     IS NULL THEN NULL
              ELSE ADD_MONTHS( "DATE", 1 )
              END AS missing_date
  FROM   your_table
)
GROUP BY ID
HAVING COUNT( missing_date ) > 0;

<强>输出

        ID MIN(MISSING_DATE) 
---------- -------------------
       123 2014-10-01 00:00:00 
       456 2014-06-01 00:00:00