【问题标题】:Find all rows where start date is before a prior end date查找开始日期早于前一个结束日期的所有行
【发布时间】:2015-09-23 18:56:33
【问题描述】:

有没有办法根据用户拉回所有具有重叠日期时间的记录?

例如;

TableA 有以下几行;

TrainerID            StartTime            EndTime
1234                 10-1-2015 08:30      10-1-2015 09:00 
1234                 10-1-2015 08:45      10-1-2015 09:15
1234                 10-1-2015 09:30      10-1-2015 10:00
2345                 10-1-2015 08:45      10-1-2015 09:15
2345                 10-1-2015 09:30      10-1-2015 10:00

我需要一个只能提取以下记录的查询,因为它的开始时间早于培训师的上一个结束时间(双重预订):

1234                 10-1-2015 08:45      10-1-2015 09:15

【问题讨论】:

    标签: sql sql-server tsql sql-server-2012


    【解决方案1】:

    下面的 EXIST 代码应该会给你答案。代码确保冲突条目的开始时间在主列表条目开始之前,而冲突的开始时间仍然在邮件列表条目的开始时间之后。

    SELECT * 
    FROM tblTest clashing
    WHERE EXISTS 
    (
        SELECT 1
        FROM tblTest mainlist
        WHERE clashing.trainderid = mainlist.trainderid 
            AND clashing.starttime < mainlist.endtime
            AND clashing.starttime > mainlist.starttime
    )
    

    这也可以用 IN 语句编写,但 EXIST 更有效

    【讨论】:

      【解决方案2】:

      要删除重叠的日期,您可以使用:

      Demo

      CREATE TABLE #TABLEA( TrainerID INT, StartDate DATETIME, EndDate DATETIME);
        
      INSERT INTO #TABLEA
      SELECT 1234,  '10-1-2015 08:30', '10-1-2015 09:00'
      UNION ALL SELECT 1234 , '10-1-2015 08:45',    '10-1-2015 09:15'
      UNION ALL SELECT 1234 , '10-1-2015 09:30',    '10-1-2015 10:00'
      UNION ALL SELECT 2345 , '10-1-2015 08:45',    '10-1-2015 09:15'
      UNION ALL SELECT 2345 , '10-1-2015 09:30',    '10-1-2015 10:00';
      
      SELECT
        D.TrainerID,
        [StartTime] = D.StartDate,
        [EndTime] = (SELECT MIN(E.EndDate)
                     FROM #TABLEA E
                     WHERE E.EndDate >= D.EndDate
                       AND E.TrainerID = D.TrainerID
                       AND NOT EXISTS (SELECT 1
                                       FROM #TABLEA E2
                                       WHERE E.StartDate < E2.StartDate
                                         AND E.EndDate > E2.StartDate
                                         AND E.TrainerID = E2.TrainerID)) 
      FROM #TABLEA D
      WHERE NOT EXISTS ( SELECT 1
                         FROM #TABLEA D2
                         WHERE D.StartDate < D2.EndDate
                           AND D.EndDate > D2.EndDate
                           AND D.TrainerID = D2.TrainerID);
      

      【讨论】:

        【解决方案3】:

        您可以使用下面的代码来获取所需的行,但是根据您的下一个培训师 ID(即 2345)的逻辑行也将是合格的

          DECLARE @Trainers TABLE
        (
            TrainerId INT,
            Start_Time datetime,
            End_Time datetime
        )
        INSERT INTO @Trainers VALUES 
        (1234,'10-1-2015 08:30','10-1-2015 09:00 '),
        (1234,'10-1-2015 08:45','10-1-2015 09:15'),
        (1234,'10-1-2015 09:30','10-1-2015 10:00'),
        (2345 ,' 10-1-2015 08:45','10-1-2015 09:15'),
        (2345 ,' 10-1-2015 09:30 ',' 10-1-2015 10:00')
        
        
        ;WITH TrainersTemp AS
                (
                SELECT  *, ROW_NUMBER() OVER ( ORDER BY trainerid) AS rn
                FROM    @Trainers
                )
        SELECT  CX.TrainerId, CX.Start_Time, CX.End_Time
        FROM    TrainersTemp CX JOIN TrainersTemp CY
        ON      CX.rn = CY.rn + 1
        WHERE CY.End_Time < CX.Start_Time
        

        Demo(SQL fiddle 又挂了)

        或者如果您想查看除错误行之外的所有行,请使用以下代码

         ;WITH TrainersTempAll AS
                (
                SELECT  *, ROW_NUMBER() OVER ( ORDER BY trainerid) AS rn
                FROM    @Trainers
                )
        SELECT  CX.TrainerId, CX.Start_Time, CX.End_Time
        FROM    TrainersTempAll CX JOIN TrainersTempAll CY
        ON      CX.rn = CY.rn + 1
        

        【讨论】:

        • Trainer "2345" 虽然没有双订,所以我不想拉那排。那是我的问题;当我只关心教练是否在某个日期被重复预订时,我会一直拉所有行。
        【解决方案4】:

        首先,您应该按 trainerId 和 Start_time 排序。然后以正确的条件连接两个表。

        试试这个查询:

        ;WITH TrainersTemp AS
        (
            SELECT  *, ROW_NUMBER() OVER ( ORDER BY trainerid, Start_Time) AS row_num
            FROM    Trainers
        )
        select t2.* from TrainersTemp t1 
        join TrainersTemp t2 on t1.TrainerId = t2.TrainerId and t1.row_num = t2.row_num-1
        where t2.Start_Time<t1.End_Time
        

        【讨论】:

          【解决方案5】:

          当您使用 SQL Server 2012 时,您可以使用LAG 函数,这可能比自联接更有效。查询也变得非常简单。

          对于每一行,LAG 为您提供前一行的EndTime(由TrainerID 分区)。然后将当前行中的StartTime 与上一行中的EndTime 进行比较。

          SQL Fiddle

          WITH
          CTE
          AS
          (
            SELECT
              TrainerID
              ,StartTime
              ,EndTime
              ,LAG(EndTime) OVER(PARTITION BY TrainerID ORDER BY StartTime) AS PrevEndTime
            FROM TableA
          )
          SELECT
              TrainerID
              ,StartTime
              ,EndTime
          FROM CTE
          WHERE StartTime < PrevEndTime
          ;
          

          结果

          | TrainerID |                 StartTime |                   EndTime |
          |-----------|---------------------------|---------------------------|
          |      1234 | October, 01 2015 08:45:00 | October, 01 2015 09:15:00 |
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-09-18
            • 1970-01-01
            • 2014-11-27
            • 1970-01-01
            • 1970-01-01
            • 2020-10-05
            相关资源
            最近更新 更多