2

如果我有下面这张表

   id         time
   start      08.00 AM 
   stop       09.00 AM
   stop       09.30 AM
   start      09.30 AM
   start      11.00 AM
   start      11.30 AM
   stop       11.40 AM
   stop       12.00 PM

我想要的输出只需要每次第一次启动停止后的每次启动最后一次停止

有什么解决办法吗?

这就是我想要的输出:

   id         time
   start      08.00 AM 
   stop       09.00 AM
   start      09.30 AM
   stop       11.40 AM
   stop       12.00 PM
4

4 回答 4

4

Whitout 对每一行都有任何主键或一些不同的 id ......我想到的唯一解决方案是:

select rn, id , time
from
(select ROW_NUMBER() over (order by time) as rn, id, time from test 
where id = 'start'
union
select ROW_NUMBER() over (order by time) as rn, id, time from test 
where id = 'stop'
) d
order by rn

基本上我在开始行和停止行之间建立了一个联合,如下所示:

 (select ROW_NUMBER() over (order by time) as rn, id, time from test 
    where id = 'start'
    union
    select ROW_NUMBER() over (order by time) as rn, id, time from test 
    where id = 'stop'
    ) d

返回:

    1   start   08.00
    2   start   11.00
    3   start   12.00
    4   start   13.00
    1   stop    09.00
    2   stop    10.00
    3   stop    14.00
    4   stop    15.00

从原始输入:

id          time
start   08.00
stop    09.00
stop    10.00
start   11.00
start   12.00
start   13.00
stop    14.00
stop    15.00

现在您只需按他们自己的行号对它们进行排序......就是那个 rn。

最后,您将拥有:

1   start   08.00
1   stop    09.00
2   start   11.00
2   stop    10.00
3   start   12.00
3   stop    14.00
4   start   13.00
4   stop    15.00

@注意:我的示例值与您的值接近...但是虚构的...

于 2013-01-29T08:13:40.383 回答
2

我有一些替代方案,它将以不同的格式给出结果。但它确实返回了请求的信息。

SELECT
  MIN([main].[Start]) AS [Start],
  [main].[End] AS [Stop],
  DATEDIFF(minute, MIN([main].[Start]), [main].[End]) AS [Minutes]
FROM
(
  SELECT
    [sub].[Start],
    MIN([sub].[End]) AS [End]
  FROM
  (
    SELECT
      [start].[time] AS [Start],
      [start].[id] AS [StartingStatus],
      [end].[time] AS [End],
      [end].[id] AS [EndingStatus]
    FROM [Log] [start],  [Log] [end]
    WHERE [start].[id] = 'start' 
      AND [start].[time] < [end].[time]
      AND [start].[id] <> [end].[id]
  ) AS [sub]
  GROUP BY
    [sub].[Start],
    [sub].[StartingStatus]
) AS [main]
GROUP BY
  [main].[End]

基本上,它首先选择所有记录where [id] = 'start'。然后它会查找所有具有较晚时间和 的记录where [id] <> 'start'

在这些记录中,它按每个“开始”分组并确定第一个“停止”时间。然后将这些记录再次分组,以找到每个“停止”时间的第一个“开始”时间。

结果如下所示:

+--------------------------------+--------------------------------+---------+
| START                          | STOP                           | MINUTES |
+================================+================================+=========+
| January, 29 2013 08:00:00+0000 | January, 29 2013 09:00:00+0000 | 60      |
+--------------------------------+--------------------------------+---------+
| January, 29 2013 09:30:00+0000 | January, 29 2013 11:30:00+0000 | 120     |
+--------------------------------+--------------------------------+---------+
| January, 29 2013 11:30:00+0000 | January, 29 2013 12:00:00+0000 | 30      |
+--------------------------------+--------------------------------+---------+

小提琴是在这里找到的。

PS:这个答案是基于我在这里的回答。

于 2013-01-29T08:55:58.287 回答
2
 ;WITH cte AS
 (
  SELECT id AS pr, [time], ROW_NUMBER() OVER(ORDER BY [time]) AS Id,
         COUNT(*) OVER() AS cnt        
  FROM dbo.test21 t1
  ), cte2 AS
 (
  SELECT Id, pr, [time], pr AS prStart, [time] AS StopTime, pr AS prStop, [time] AS StartTime
  FROM cte
  WHERE Id = 1
  UNION ALL
  SELECT c1.Id, 
         CASE WHEN c1.pr != c2.pr OR c1.Id = c1.cnt THEN c1.pr ELSE c2.pr END,
         CASE WHEN c1.pr != c2.pr OR c1.Id = c1.cnt THEN c1.[time] ELSE c2.[time] END,
         c1.pr, c1.[time], c2.pr, c2.[time]
  FROM cte c1 JOIN cte2 c2 ON c1.Id = c2.Id + 1
  )
  SELECT pr, [time], MIN(StartTime) AS StartTime,
         MAX(DATEDIFF(minute, StartTime, [time])) AS Interval
  FROM cte2
  GROUP BY pr, [time]

SQLFiddle上的演示

于 2013-01-29T08:58:41.897 回答
1

在评论中做出澄清后,这变成了一个经典的问题。

假设这是 SQL Server 2005+,您可以使用以下方法:

WITH partitioned AS (
  SELECT
    *,
    grp = ROW_NUMBER() OVER (ORDER BY time, CASE id WHEN 'stop' THEN 0 ELSE 1 END)
        - ROW_NUMBER() OVER (PARTITION BY id ORDER BY time)
  FROM atable
)
SELECT
  id,
  time = MIN(time)
FROM partitioned
GROUP BY
  id,
  grp
ORDER BY
  time
;
于 2013-01-29T09:07:35.910 回答