我有下表,其中包含 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
要获得带有间隙的 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;
您可以使用 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_;
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
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