查找序列中缺失的日期

问题描述 投票:0回答:4

我有下表,其中包含 ID 和日期

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
sql oracle oracle11g
4个回答
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
投票

您可以使用 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_;

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 

0
投票
    with 
    -- Unique dates in the source table
    unique_dates as(
      SELECT 
      distinct event_date
      FROM date_table
    ),
    -- Find the next available date for each date
    dates_lagged as (
      SELECT *
      , LAG(event_date,1) OVER (ORDER BY event_date DESC) as next_day
      FROM unique_dates
    )
    -- Gives you the beginning of each missing date timeframe and the number of days missing
    SELECT event_date
    , next_day
    , date_diff(next_day,event_date,DAY) as missing_days 
    FROM dates_lagged
    WHERE date_diff(next_day,event_date,DAY)!=1
© www.soinside.com 2019 - 2024. All rights reserved.