如何处理SQL Server中的时间间隔?

时间:2017-07-22 07:07:57

标签: sql sql-server

我遵循时间间隔逻辑。如果在结束时间和开始时间之间有任何时间间隔,我们必须隔离该数据。

我曾经这样查询,

DECLARE @EMP_DETAILS TABLE
                     (ID INT,
                      EMP_ID INT, 
                      START_TIME VARCHAR(10),
                      END_TIME VARCHAR(10)
                     )

INSERT INTO @EMP_DETAILS
    SELECT 1, 50, '09:30', '10:30'
    UNION
    SELECT 2, 50, '10:30', '11:45'
    UNION
    SELECT 3, 50, '11:45', '12:15'
    UNION
    SELECT 4, 50, '12:15', '13:40'
    UNION
    SELECT 5, 50, '14:00', '14:40'
    UNION
    SELECT 6, 50, '14:40', '15:10'
    UNION
    SELECT 7, 50, '15:10', '18:00'


SELECT 
    A.EMP_ID, A.START_TIME, A.END_TIME,
    B.START_TIME, B.END_TIME 
FROM 
    @EMP_DETAILS A 
LEFT JOIN 
    @EMP_DETAILS B ON A.END_TIME = B.START_TIME
                   AND A.EMP_ID = B.EMP_ID

我的预期输出应如下所示:

EMP_ID  START_TIME  END_TIME  RN
---------------------------------
50      09:30       10:30     1
50      10:30       11:45     1
50      11:45       12:15     1
50      14:00       14:40     2
50      14:40       15:10     2

我有希望,你清楚我要说的是什么......

提前致谢。

2 个答案:

答案 0 :(得分:0)

我确信有一种方法可以在单个查询中计算RN列,但我现在无法想到它。因此,通过使用游标,以下内容可以创建您想要的内容:

DECLARE @EMP_DETAILS TABLE (
  ID INT,
  EMP_ID INT, 
  START_TIME VARCHAR(10),
  END_TIME VARCHAR(10)
)
DECLARE @OUTPUT TABLE (
  ID INT,
  EMP_ID INT,
  START_TIME VARCHAR(10),
  END_TIME VARCHAR(10),
  RN INT NULL
)

INSERT INTO @EMP_DETAILS VALUES
(1, 50, '09:30', '10:30'),
(2, 50, '10:30', '11:45'),
(3, 50, '11:45', '12:15'),
(4, 50, '12:15', '13:40'),
(5, 50, '14:00', '14:40'),
(6, 50, '14:40', '15:10'),
(7, 50, '15:10', '18:00')

INSERT INTO @OUTPUT
SELECT A.ID, A.EMP_ID, A.START_TIME, A.END_TIME, NULL
FROM   @EMP_DETAILS A 
       INNER JOIN @EMP_DETAILS B ON A.EMP_ID = B.EMP_ID AND A.END_TIME = B.START_TIME

DECLARE @ID INT, @I INT, @J INT = 1

SELECT @I = MIN(ID) - 1
FROM   @OUTPUT

DECLARE CR CURSOR LOCAL FOR
  SELECT ID
  FROM   @OUTPUT
  ORDER BY ID

OPEN CR
FETCH NEXT FROM CR INTO @ID

WHILE @@FETCH_STATUS = 0
BEGIN
  IF @ID > @I + 1
    SET @J = @J + 1

  UPDATE @OUTPUT
  SET    RN = @J
  WHERE  ID = @ID

  SET @I = @ID

  FETCH NEXT FROM CR INTO @ID
END

CLOSE CR
DEALLOCATE CR

SELECT EMP_ID, START_TIME, END_TIME, RN
FROM   @OUTPUT
ORDER BY ID

我没有使用LEFT JOIN,而是使用INNER JOIN来消除不需要的行。然后,通过使用RN移动@OUTPUT表中的记录来计算CURSOR列,以查找ID序列中的中断。如果有休息,那么我们增加RN。这假定ID在实际数据中永远不会丢失数字。

这是上述查询的输出:

EMP_ID      START_TIME END_TIME   RN
----------- ---------- ---------- -----------
50          09:30      10:30      1
50          10:30      11:45      1
50          11:45      12:15      1
50          14:00      14:40      2
50          14:40      15:10      2

答案 1 :(得分:0)

简单:

select sq.EMP_ID, sq.START_TIME, sq.END_TIME, sq.RN
from (
  select e.*,
    sum(case when xt.ID is not null then 0 else 1 end)
    over(partition by e.emp_id order by e.start_time) + 1 as [RN],
    xt.ID as [SameRange]
  from @EMP_DETAILS e
    left join @EMP_DETAILS xt on xt.EMP_ID = e.EMP_ID and xt.START_TIME = e.END_TIME
      and xt.ID != e.ID
) sq
where sq.SameRange is not null;

排除不需要的行很简单,可以使用简单的left join来完成。然而,对它们进行编号有点棘手。您需要SQL Server 2012或更高版本才能运行总计 - sum(...) over(order by ...) - 才能正常工作。

如果您的表包含重复或零间隔(即同一行中的start_time = end_time),则此处可能出现唯一可能的问题。最有可能的是,您需要使用子查询替换表,该子查询将提供不同的值。