2008-11-19 73 views
2

这是一个SQL问题我无法用简单的查询包裹头部是否有可能?SQL汇总时间范围的最小/最大活动时间

的数据集是(添加为了便于理解,字母):

Start  End 
10:01  10:12  (A) 
10:03  10:06  (B) 
10:05  10:25  (C) 
10:14  10:42  (D) 
10:32  10:36  (E) 

所需的输出是:

PeriodStart New  ActiveAtEnd MinActive MaxActive 
09:50   0   0    0   0 
10:00   3 (ABC) 2 (AC)   0   3 (ABC) 
10:10   1 (D)  2 (CD)   1 (C)  2 (AC or CD) 
10:20   0   1 (D)   1 (C)  2 (CD) 
10:30   1 (E)  1 (D)   1 (D)  2 (DE) 
10:40   0   0    0   1 (D) 
10:50   0   0    0   0 

所以,所需要的查询是所述第一表的摘要,计算最短重叠时间段(Start-End)和10分钟内第一个表格的最大重叠时间段(Start-End)。

'New'是在汇总期中具有Start的行数。 'ActiveAtEnd'是在汇总期结束时活动的行数。

我使用的是Oracle,但我确定可以调整解决方案。不允许存储过程 - 只是简单的SELECT/INSERT(允许视图)。它也确定每运行10一个SQL命令分钟输出(因为一旦填充,这将是它如何保持最新状态。

感谢您的任何想法,包括“不可能” ;-)

+0

什么样的列是开始和结束?他们是日期还是varchar2? – 2008-11-19 12:42:32

回答

0

新和ActiveAtEnd是相当简单的(假定被存储在临时变量的周期的开始和结束):

select @periodStart PeriodStart 
, @periodEnd PeriodEnd 
, n.[new] 
, ae.ActiveAtEnd 
from (
select count(*) [new] 
from @times 
where [start] >= @periodStart 
and [start] < @PeriodEnd 
) n 
cross join 
(
select count(*) [ActiveAtEnd] 
from @times 
where [start] < @PeriodEnd 
and [end] >= @PeriodEnd 
) ae 

的最大和最小活性物质是硬。您可以假定一分钟的粒度,因此您需要按该粒度展开活动期以便能够探测每个片。

我不确定这在单个查询中是否可行。

0

我曾经能够解决这类问题的唯一方法是获得每一分钟时间的“开始”计数。然后您获得10分钟组的最大值(或最小值)。我无法应用基于集合的方法。

1

我正在努力与ActiveAtEnd值,但其他人都没问题。

这是MySQL:

set @active:=0; 

select 
    period, 
    sum(if(score=1, 1, 0)) New, 
    if(max(ab) > max(aa), max(ab), max(aa)) MaxActive, 
    if(min(ab) < min(aa), min(ab), min(aa)) MinActive 
from (
     select 
      period, 
      etime, 
      score, 
      @active ab, 
      @active:[email protected]+score aa 
     from (
       select 
       from_unixtime(floor(unix_timestamp(start)/600) * 600) period, 
       start etime, 
       +1 score 
       from ev 
       union all 
       select from_unixtime(floor(unix_timestamp(end)/600) * 600) period, 
       end etime, 
       -1 score 
       from ev 
      ) event order by etime 
    ) as temp 
group by period; 

最里面选择打破了原始表成一组事件 - 与用于启动事件的分数+1和-1为结束事件。 union all被使用,以便重复的事件被允许。

下一个内部选择在分数值上运行变量 - @active保存每个时间点的活动区间数的计数。选择添加当前计数之前和之后的@active值:我不知道这是多么便携。

最外面的选择会累积每个周期的结果。 '新'是'+1'分数的总和,MaxActive和MinActive两者都必须考虑(ab)之前的有效值和(aa)之后的有效值。

下面是抽查结果:

+---------------------+------+-----------+-----------+ 
| period    | New | MaxActive | MinActive | 
+---------------------+------+-----------+-----------+ 
| 2008-11-19 10:00:00 | 3 |   3 |   0 | 
| 2008-11-19 10:10:00 | 1 |   2 |   1 | 
| 2008-11-19 10:20:00 | 0 |   2 |   1 | 
| 2008-11-19 10:30:00 | 1 |   2 |   1 | 
| 2008-11-19 10:40:00 | 0 |   1 |   0 | 
+---------------------+------+-----------+-----------+ 
3

假设你也有(或创建)一个名为表与一个记录每个10分钟开始时间, 如何@Times ...

Select T.Start, 
     (Select Count(*) From testTab 
     Where Start Between T.Start 
      And DateAdd(minute, 10, T.Start)) New, 
     (Select Count(*) From testTab 
     Where Start < DateAdd(minute, 10, T.Start) 
      And EndDt > DateAdd(minute, 10, T.Start)) ActiveAtEnd, 
     (Select Max(Cnt) From 
      (Select Count(Distinct T.Which) Cnt 
      From (Select Distinct Start 
        From testTab 
        Where Start Between T.Start 
          And DateAdd(minute, 10, T.Start) 
        Union Select T.Start 
        Union Select DateAdd(minute, 10, T.Start)) Z 
      Left Join testTab T 
       On Z.Start Between T.Start And T.EndDt 
      Group By Z.Start) ZZ) MaxActive, 
     (Select Min(Cnt) From 
      (Select Count(Distinct T.Which) Cnt 
      From (Select Distinct Start 
        From testTab 
        Where Start Between T.Start 
          And DateAdd(minute, 10, T.Start) 
        Union Select T.Start               
        Union Select DateAdd(minute, 10, T.Start)) Z 
       Left Join testTab T 
       On Z.Start Between T.Start And T.EndDt 
      Group By Z.Start) ZZ) MinActive  
    From @Times T 

我创建了SQL Server作为一个表变量此表,使用

Declare @Times Table (Start datetime Primary key Not Null) 
Declare @Start DateTime 
Set @Start = '1 Nov 2008 10:00' 
While @Start < '1 Nov 2008 11:00' begin 
    Insert @Times(Start) values(@Start) 
    Set @Start = DateAdd(minute, 10, @Start) 
End 

若y ou正在使用另一种产品,请使用临时表代替...但这种方法确实需要一个表,每个十分钟“期间”有一个记录作为运行的一个钩子...

用以下数据查询生成输出如下:

start     endDt     Which 
----------------------- ----------------------- ----- 
2008-11-01 10:01:00.000 2008-11-01 10:12:00.000 A 
2008-11-01 10:03:00.000 2008-11-01 10:06:00.000 B 
2008-11-01 10:05:00.000 2008-11-01 10:25:00.000 C 
2008-11-01 10:14:00.000 2008-11-01 10:42:00.000 D 
2008-11-01 10:32:00.000 2008-11-01 10:36:00.000 E 
2008-11-01 10:22:00.000 2008-11-01 10:51:00.000 F 
2008-11-01 10:22:00.000 2008-11-01 10:23:00.000 G 

Start     New   ActiveAtEnd MaxActive MinActive 
----------------------- ----------- ----------- ----------- ----------- 
2008-11-01 10:00:00.000 3   2   3   0 
2008-11-01 10:10:00.000 1   2   2   2 
2008-11-01 10:20:00.000 2   2   4   2 
2008-11-01 10:30:00.000 1   2   3   2 
2008-11-01 10:40:00.000 0   1   2   1 
2008-11-01 10:50:00.000 0   0   1   0 

警告:空值由集合或其他SET操作消除。