【问题标题】:T-SQL Start and end date times from a single column单列的 T-SQL 开始和结束日期时间
【发布时间】:2011-10-03 16:37:31
【问题描述】:

我有一个不同资产的开/关事件表。我需要在不使用光标的情况下获取开始和停止事件时间的列表。

来源:

Item      EventDate               Event
A         2011-10-03 00:01:00     On
B         2011-10-03 00:01:00     On
A         2011-10-03 00:02:00     Off
C         2011-10-03 00:01:00     On
B         2011-10-03 00:02:00     Off
A         2011-10-03 00:02:02     On      
C         2011-10-03 00:02:05     On
A         2011-10-03 00:02:07     Off

想要的结果:

Item      Start                   End
A         2011-10-03 00:01:00     2011-10-03 00:02:00
A         2011-10-03 00:02:02     2011-10-03 00:02:07
B         2011-10-03 00:01:00     2011-10-03 00:01:00
C         2011-10-03 00:01:00     2011-10-03 00:02:05

【问题讨论】:

  • 您会曾经在某个项目中使用重叠的时段吗?
  • 尝试了子查询和 cte,但运气不佳。这应该很简单。我真的想把它保存在服务器上。
  • 这里几乎解决了同样的问题stackoverflow.com/questions/6898289/…
  • 通过一点点操作,您可以使用聚合函数最小值和最大值,就像我在手术中所做的那样(我使用了 @Adrian 的数据)

标签: sql sql-server tsql


【解决方案1】:

这是解决方案,每个人都可以验证概念证明。

我注意到COff 事件被标记为新的On。我解决了这个问题,但这也导致我编写了一个解决方案,允许有一个已经开始但尚未结束的事件,所以我加入了一个开放式事件D

此外,我的解决方案适用于重叠时段。

declare @YourTable table (Item varchar(10), 
                          EventDate datetime, 
                          Event varchar(10))

insert into @YourTable values
('A',         '2011-10-03 00:01:00',     'On'),
('B',         '2011-10-03 00:01:00',     'On'),
('A',         '2011-10-03 00:02:00',     'Off'),
('C',         '2011-10-03 00:01:00',     'On'),
('B',         '2011-10-03 00:02:00',     'Off'),
('A',         '2011-10-03 00:02:02',     'On'),  
('C',         '2011-10-03 00:02:05',     'Off'),
('A',         '2011-10-03 00:02:07',     'Off'),
('D',         '2011-10-03 00:02:02',     'On')  

select tOn.Item, tOn.EventDate Start, tOff.EventDate [End]
from (
select Item, EventDate, 
       ROW_NUMBER() Over(Partition by Item order by EventDate) EventID
from @YourTable where Event = 'On'
) tOn
LEFT JOIN (
select Item, EventDate, 
       ROW_NUMBER() Over(Partition by Item order by EventDate) EventID
from @YourTable where Event = 'Off'
) tOff
on (tOn.Item = tOff.Item and tOn.EventID = tOff.EventID)

解释

我们将数据集分为 2 个:On events 和 Off events。每个都包含一个编号的行,当Item 更改时重新启动。

基本上,我们有先进先出:第一个On 将被第一个Off 关闭,因此在这种方法下,此查询将支持重叠句点。所以A 的每个On 事件都会有它的Event ID,它会链接到对应的Off Event ID

LEFT JOIN 将支持开放式期间。

【讨论】:

  • 实际上 C 的数据是有意的。可以记录多个关闭和打开。我仍在寻找一种清理它们的好方法。
  • 根据所需输出的最后一行:C 2011-10-03 00:01:00 2011-10-03 00:02:05,它看起来不是故意的。不管怎样,我很乐意提供帮助。
【解决方案2】:

未经测试...

;WITH myCTE AS
(
   SELECT *,
         ROW_NUMBER() OVER (PARTITION BY Item ORDER BY EventDate) AS rn
   FROM MyTable
)
SELECT
   M1.Item,
   M1.EventDate AS Start,
   M2.EventDate AS End
FROM
   myCTE M1
   JOIN
   myCTE M2 ON M1.Item = M2.Item AND M1.rn+1 = M2.rn
WHERE
   M1.Event = 'On'
   AND
   M2.Event = 'Off';

【讨论】:

  • 看看我的解决方案,看看你喜欢它。它也支持重叠时段和开放式结束时段
【解决方案3】:
declare @YourTable table (Item varchar(10), EventDate datetime, Event varchar(10)) 

insert into @YourTable values 
('A','2011-10-03 00:01:00''On'), 
('B','2011-10-03 00:01:00','On'), 
('A','2011-10-03 00:02:00','Off'), 
('C','2011-10-03 00:01:00','On'), 
('B','2011-10-03 00:02:00','Off'), 
('A','2011-10-03 00:02:02','On'),   
('C','2011-10-03 00:02:05','Off'), 
('A','2011-10-03 00:02:07','Off'), 
('D','2011-10-03 00:02:02','On')   

;with a as
(
select item, eventdate, event, ROW_NUMBER() Over(Partition by Item order by EventDate) RN 
from @YourTable
),
b as (
select item, eventdate, 0 e, rn, event from a where rn = 1
union all
select b.item, a.eventdate, case when b.event = 'Off' then b.e+1 else b.e end, a.rn, a.event
from b 
join a on b.rn + 1 = a.rn and a.item = b.item
)
select item, min(eventdate) Start, max(eventdate) [End]
 from b
group by item, e
order by item, e

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-10
    相关资源
    最近更新 更多