【问题标题】:Overlapping Dates Exclusion重叠日期排除
【发布时间】:2018-04-24 06:07:33
【问题描述】:

这可能是一个相当简单的问题,但对我来说仍然是一个挑战。我有一个包含 4 个字段 Person_id、Store_id、startdate 和 enddate 的表。对于 person_id 的特定值,可以有许多具有不同开始和结束日期的记录。如果当前结束日期到下一个开始日期超过 24 小时,我需要在这里找到时间间隔。这里的问题是对于每个 person_id 可能有重叠时期的记录。

示例 1:

Person_id       Store_ID          Startdate           enddate
10000351067      10000232561      2010-04-08          2010-08-06
10000351067      10000232561      2016-09-09          2016-09-16
10000351067      10000232561      2016-09-16          2016-10-03
10000351067      10000232561      2016-10-03          2016-10-07
10000351067      10000232561      2016-10-07          2017-01-17
10000351067      10000232561      2017-01-17          2018-04-05
**10000351067      10000232561      2017-06-16          2017-06-20**
10000351067      10000232561      2018-04-05          NULL

示例2:

10000193858      10000225875      2016-07-13          2016-08-03
10000193858      10000225875      2016-08-03          2017-05-17
10000193858      10000225875      2017-05-17          2017-06-05
10000193858      10000225875      2017-05-31          2017-06-05
10000193858      10000225875      2017-06-05          2017-06-13
10000193858      10000225875      2017-06-13          2017-08-16
10000193858      10000225875      2017-08-07          2017-08-16
10000193858      10000225875      2017-08-16          2017-08-18
10000193858      10000225875      2017-08-18          2017-08-31
10000193858      10000225875      2017-08-31          2018-01-05
**10000193858      10000225875      2017-11-13          2017-11-20**
10000193858      10000225875      2018-01-05          NULL

在所有情况下都需要保留“开始日期”最早的记录。在有多条记录具有相同最早的“开始日期”的情况下,需要保留具有最大“结束日期”的记录。我尝试使用以下查询,但没有成功(可能我做错了什么)。

CREATE TABLE #ordered_removal_list(
                [ID_New] [int] IDENTITY(1,1) NOT NULL,
                [person_id] [bigint] NULL,
                [Store_ID] [bigint] NULL,
                [started_at] [datetime] NULL,
                [ended_at] [datetime] NULL,     
)
INSERT INTO #ordered_removal_list 
(person_id,Store_ID,started_at,ended_at)
SELECTperson_id,Store_ID,started_at,ended_at into #test FROM Temp_Data
;WITH cte 
AS
(
SELECT ord1.person_id, ord1.started_at, ord1.ended_at, next1.started_at as next1_start,
Last1.started_at as last1_start, CASE WHEN DATEDIFF (HOUR, last1.ended_at, ord1.started_at) > 23 THEN 'GAP' ELSE 'NO_GAP' END as 'gap'
FROM #test ord1
LEFT JOIN #test next1 on next1.[ID_New] = ord1.[ID_New] + 1 and ord1.person_id = next1.person_id)
SELECT * FROM cte 
where gap = 'GAP'

我无法排除上述示例中以红色标记的重叠日期。任何建议(最好是代码示例)

结果集:

示例 1)如果我排除重叠日期 10000351067、10000232561、2017-06-16、2017-06-20 那么它们是当前记录结束日期到下一个开始日期之间的时间间隔,即整个时间段之间没有时间间隔与下一个时期相比。

示例 2)如果我排除重叠日期 10000193858、10000225875、2017-11-13、2017-11-20 那么它们是当前记录结束日期到下一个开始日期之间的时间间隔,即整个时间段之间没有时间间隔与下一个时期相比。

谢谢!

【问题讨论】:

  • 编辑您的问题并提供您想要的结果。问题含糊不清(哪个日期/时间的 24 小时)。
  • 添加到@GordonLinoff 的评论中,在选择查询中,表名-> CTE_1,可以看到#test,但没有任何具有这些名称的表。
  • @RahulJain,数据已从临时数据永久表加载到测试表中。
  • 标记您正在使用的RDBMS(带有版本)
  • @uzi Microsoft SQL Server 2008

标签: sql sql-server


【解决方案1】:

给你(PostgreSQL 中的示例):

with attendance_ext as (
select a.*, (select min(startdate) from attendance x 
  where x.startdate > a.startdate) as nextstart
  from attendance a)
select * from attendance_ext
  where (startdate + interval '24 hours') < nextstart;

假设你的桌子是这样的:

create table attendance (
  person_id int, 
  store_id int, 
  startdate timestamp, 
  enddate timestamp
);

insert into attendance (person_id, store_id, startdate, enddate) 
  values (1, 1, '2010-04-08', '2010-08-06');
insert into attendance (person_id, store_id, startdate, enddate) 
  values (1, 1, '2016-09-09', '2016-09-16');
insert into attendance (person_id, store_id, startdate, enddate) 
  values (1, 1, '2016-09-16', '2016-10-03');
insert into attendance (person_id, store_id, startdate, enddate) 
  values (1, 1, '2016-10-03', '2016-10-07');

【讨论】:

    【解决方案2】:

    您似乎正在尝试排除被其他行覆盖的行。如果是这样,试试这个查询

    select
        *
    from
        myTable a
    where
        not exists (
            select 1
            from myTable b
            where
                a.Person_id = b.Person_id and a.Store_ID = b.Store_ID
                and a.Startdate > b.Startdate and a.enddate < b.enddate
        )
    

    【讨论】:

      【解决方案3】:

      这是一个似乎适用于所提供数据的解决方案。它的工作原理是检查没有重叠的记录 (p) 取代当前 (c) 记录。如果重叠记录在当前记录之前开始,或者与当前记录同时开始但在当前记录之后结束,则重叠记录将取代当前记录 开始或结束日期列中的 NULL 分别被视为时间的开始或结束。

      要确定记录优先级,请添加一个行号列 (RN),它还可以防止将记录与其自身进行比较。比较记录时,前一条记录的行号会小于当前记录。

      完成后,剩下的就是检查是否有重叠,请参阅此 SQL Fiddle 以获取示例(请注意,我在您的第二个数据集中添加了 1 个具有并发开始时间的样本记录以测试该条件):

      with dta as (
        select row_number()
          over (partition by person_id, store_id
                order by case when startdate is null then 1 else 0 end
                       , startdate
                       , case when enddate is null then 1 else 2 end
                       , enddate desc) rn
             , a.*
          from YourData a
       )
       select * from dta c
       where not exists (
           select 1 from dta p
            where p.person_id = c.person_id
              and p.store_id = c.store_id
              -- Establish precedence
              and p.rn < c.rn
              -- Detect overlaps
              and (p.startdate is null or p.startdate < c.enddate or c.enddate is null)
              and (c.startdate is null or c.startdate < p.enddate or p.enddate is null)
         )
      
      order by Person_id, store_id, startdate
      

      Results

      | rn |   Person_id |    Store_ID |            Startdate |              enddate |
      |----|-------------|-------------|----------------------|----------------------|
      |  1 | 10000193858 | 10000225875 | 2016-07-13T00:00:00Z | 2016-08-03T00:00:00Z |
      |  2 | 10000193858 | 10000225875 | 2016-08-03T00:00:00Z | 2017-05-17T00:00:00Z |
      |  3 | 10000193858 | 10000225875 | 2017-05-17T00:00:00Z | 2017-06-05T00:00:00Z |
      |  5 | 10000193858 | 10000225875 | 2017-06-05T00:00:00Z | 2017-06-13T00:00:00Z |
      |  6 | 10000193858 | 10000225875 | 2017-06-13T00:00:00Z | 2017-08-16T00:00:00Z |
      |  8 | 10000193858 | 10000225875 | 2017-08-16T00:00:00Z | 2017-08-18T00:00:00Z |
      |  9 | 10000193858 | 10000225875 | 2017-08-18T00:00:00Z | 2017-08-31T00:00:00Z |
      | 11 | 10000193858 | 10000225875 | 2017-08-31T00:00:00Z | 2018-01-05T00:00:00Z |
      | 13 | 10000193858 | 10000225875 | 2018-01-05T00:00:00Z |               (null) |
      |  1 | 10000351067 | 10000232561 | 2010-04-08T00:00:00Z | 2010-08-06T00:00:00Z |
      |  2 | 10000351067 | 10000232561 | 2016-09-09T00:00:00Z | 2016-09-16T00:00:00Z |
      |  3 | 10000351067 | 10000232561 | 2016-09-16T00:00:00Z | 2016-10-03T00:00:00Z |
      |  4 | 10000351067 | 10000232561 | 2016-10-03T00:00:00Z | 2016-10-07T00:00:00Z |
      |  5 | 10000351067 | 10000232561 | 2016-10-07T00:00:00Z | 2017-01-17T00:00:00Z |
      |  6 | 10000351067 | 10000232561 | 2017-01-17T00:00:00Z | 2018-04-05T00:00:00Z |
      |  8 | 10000351067 | 10000232561 | 2018-04-05T00:00:00Z |               (null) |
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多