SQL Server - 查找包含重叠日期的日期之间的差距

时间:2013-10-14 17:03:41

标签: sql sql-server

我最近的任务是找到就业日期之间的差距,其中差距被定义为从一个工作结束到下一个工作开始的时间跨度超过30天,并且能够提出一个适合的查询,见下文:

WITH GapsInEmployment AS
(
    SELECT 
    -1 AS DriverQualificationApplicationEmploymentGapId
    ,E1.DriverQualificationApplicationId
    ,E1.EndDate AS EmploymentGapBeginDate
    ,E2.StartDate AS EmploymentGapEndDate
    ,(
        CASE 
            WHEN ISNULL(DATEDIFF(DD, E1.EndDate, E2.StartDate), 0) < 0 THEN 0
            ELSE DATEDIFF(DD, E1.EndDate, E2.StartDate)
        END
        ) AS DaysLapsedBetweenEmployment
        ,NULL AS ReasonForEmploymentGap
    FROM @EmploymentGapInfo E1
    LEFT JOIN @EmploymentGapInfo E2 
        ON E1.RowNum = E2.RowNum - 1
)

SELECT *
FROM GapsInEmployment
WHERE DaysLapsedBetweenEmployment > 30;

我正在对一条记录进行比较,到下一条记录,看看是否在第一条记录的结束日期和第二条记录的开始日期之间有30天的时间,这对于“正常”工作正常“案件,即就业期间不重叠的情况。那个特定的案例出现在某个人在特定时间段内有多个工作的情况下,而工作A的时间段是在员工有工作B的时间段之间。这是与上述查询一起运行的测试数据:

DECLARE @EmploymentGapInfo TABLE
(
    RowNum INT IDENTITY(1, 1)
    ,DriverQualificationApplicationEmploymentId INT
    ,DriverQualificationApplicationId INT
    ,StartDate DATETIME
    ,EndDate DATETIME
);
INSERT INTO @EmploymentGapInfo
SELECT -1, 766, '10/14/2003', '11/07/2003';

INSERT INTO @EmploymentGapInfo
SELECT -1, 766, '08/28/2006', '06/15/2011';

INSERT INTO @EmploymentGapInfo
SELECT -1, 766, '08/22/2011', '10/23/2012';

INSERT INTO @EmploymentGapInfo
SELECT -1, 766, '06/01/2012', '07/01/2012';

INSERT INTO @EmploymentGapInfo
SELECT -1, 766, '11/01/2012', '03/05/2013';

INSERT INTO @EmploymentGapInfo
SELECT -1, 766, '10/14/2013', NULL;

如果您运行查询,则错误地计算07/01/2012和11/01/2012之间的就业差距,这是不正确的,因为该记录的开始日期和结束日期在前一记录之间开始。查询应为间隙生成以下结果集:

11/07/2003 - &gt; 2006年8月28日

06/15/2011 - &gt; 2011年8月22日

03/05/2013 - &gt;二零一三年十月十四日

我的问题是,我正试图想出一种没有光标正确计算的方法,因为我一直在尝试的方式将涉及我循环遍历EmploymentGapInfo表变量中的每条记录,并且一旦我有该记录的开始日期和结束日期再次遍历该表,以查看开始日期和结束日期是否与表中的任何其他记录重叠。

有什么办法可以用基于集合的方法解决这个问题而不是尝试使用游标?这会是一个问题,可以从业务层完成而不是尝试在数据库中解决它吗?

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:4)

sql server 2012及更高版本的强大解决方案。所有归功于A Boucher的问题https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:529176000346581356

select *
from (
      select 
       max(enddate) over (order by startdate) start_range
       ,lead(startdate) over (order by startdate) end_range
      from @EmploymentGapInfo
    ) as c
where c.start_range < c.end_range

答案 1 :(得分:0)

您可以创建一个临时表,其中@EmploymentGapInfo的所有日期按日期按升序排序。之后,更容易找出差距。

获取所有日期的查询可能如下所示:

select distinct StartDate 'GDate'
from @EmploymentGapInfo
union
select distinct EndDate 
from @EmploymentGapInfo

答案 2 :(得分:0)

也许是老帖子......但是答案就是这样:

首先,您应该消除具有重叠范围的可能性,并将结果表示在非重叠范围列表中。这不是一件容易的事,你可以通过这个查询来实现它:

    SELECT *
    INTO #TEMP
    FROM
    (
          SELECT DriverQualificationApplicationEmploymentId, DriverQualificationApplicationId, Min(NewStartDate) StartDate, MAX(EndDate) EndDate
          FROM
          (
                SELECT DriverQualificationApplicationEmploymentId, DriverQualificationApplicationId, StartDate, EndDate,
                      NewStartDate = Range_UNTIL_NULL.StartDate + NUMBERS.number,
                      NewStartDateGroup =     DATEADD(d, 
                                                  1 - DENSE_RANK() OVER (PARTITION BY DriverQualificationApplicationEmploymentId, DriverQualificationApplicationId ORDER BY Range_UNTIL_NULL.StartDate + NUMBERS.number), 
                                                  Range_UNTIL_NULL.StartDate + NUMBERS.number)
                FROM 
                (
                      SELECT 
                            DriverQualificationApplicationEmploymentId, DriverQualificationApplicationId, StartDate, ISNULL(EndDate, dateadd(d,1,StartDate)) AS EndDate
                      FROM @EmploymentGapInfo T1
                      WHERE
                            NOT  EXISTS (   SELECT * 
                                            FROM @EmploymentGapInfo t2 
                                            WHERE  T1.DriverQualificationApplicationEmploymentId = t2.DriverQualificationApplicationEmploymentId AND
                                                   T1.DriverQualificationApplicationId = T2.DriverQualificationApplicationId and 
                                                   T1.StartDate > T2.StartDate AND T2.EndDate IS NULL
                                        )
                )  AS Range_UNTIL_NULL
                CROSS APPLY  Enumerate ( ABS(DATEDIFF(d, StartDate, EndDate))) AS NUMBERS
                      ) X
          GROUP BY DriverQualificationApplicationEmploymentId, DriverQualificationApplicationId, NewStartDateGroup
    ) OVERLAPED_RANGES_WITH_COUNT
    ORDER BY DriverQualificationApplicationEmploymentId, DriverQualificationApplicationId, StartDate    

然后你可以计算超过30天的差距:

SELECT 
    EndDate AS StartGap, 
    ( SELECT MIN(StartDate) FROM #temp t3 WHERE t3.startdate  > t1.endDate) AS EndGap 
FROM #TEMP t1
WHERE EndDate + 30 < (SELECT Min(startDate) FROM #temp t2 WHERE t2.startdate  > t1.endDate)