SQL-确定当前活动记录的计数

SQL-确定当前活动记录的计数,sql,sql-server-2005,Sql,Sql Server 2005,我有一个包含以下信息的表: Conf_Start_Time Part_Start_Time Part_End_Time 如果t介于部分开始时间和部分结束时间之间,则记录在时间t被认为是活动的 我想做的是分析所有记录,以确定给定一天有多少记录处于活动状态。我建议的解决方案是循环一天中的每一分钟(比如从早上6点到晚上9点),并检查当天的每条记录,以确定用户是否在指定的时间t处于活动状态 SQL中是否有解决方案,或者我是否应该继续使用代码解决方案 在代码中,我将把所有记录都放到内存中,循环时间(早上

我有一个包含以下信息的表:

Conf_Start_Time
Part_Start_Time
Part_End_Time
如果t介于
部分开始时间
部分结束时间
之间,则记录在时间t被认为是活动的

我想做的是分析所有记录,以确定给定一天有多少记录处于活动状态。我建议的解决方案是循环一天中的每一分钟(比如从早上6点到晚上9点),并检查当天的每条记录,以确定用户是否在指定的时间t处于活动状态

SQL中是否有解决方案,或者我是否应该继续使用代码解决方案

在代码中,我将把所有记录都放到内存中,循环时间(早上6点到晚上9点),并在指定的日期测试每条记录,以确定它在当前时间是否处于活动状态。如果它是活动的,我会增加一个计数器,如果不是,继续下一条记录。下次,重新初始化计数器,继续循环一天

我们正在使用SQLServer2005

更新:我要寻找的输出将是从早上6点到晚上9点的最大并发使用量数组

Record  Conf_Start_Time    Part_Start_Time     Part_End_Time
1.      6/5/2012 13:40:00  6/5/2012 13:41:23   6/5/2012 13:45:27
2.      6/5/2012 13:40:00  6/5/2012 13:40:23   6/5/2012 13:47:29
3.      6/5/2012 13:40:00  6/5/2012 13:42:55   6/5/2012 13:44:17
因此,在13:40:00时,0条记录处于活动状态;13:41:00时,1条记录处于活动状态;13:42:00时,2条记录处于活动状态;13:43:00时,3条记录处于活动状态


我需要每天每分钟的数据。然后是这个月的每一天。这种类型的循环甚至可以在SQL中完成吗?

如果您希望所有记录都在2012年8月7日处于活动状态,请执行以下操作:

select * from your_table
where '2012-08-07' between Part_Start_Time and Part_End_Time
试试这个:

DECLARE @auxDate datetime

SELECT *
  FROM your_table
 WHERE @auxDate BETWEEN Part_Start_Time AND Part_End_Time

子句是包容性的,如果您不想包含一些日期,请考虑使用:

DECLARE @auxDate datetime

SELECT *
  FROM your_table
 WHERE @auxDate >= Part_Start_Time
   AND @auxDate <= Part_End_Time
DECLARE@auxDate-datetime
挑选*
从你的桌子上
其中@auxDate>=部分开始时间

和@auxDate下面使用相关子查询来获取所需的数字。这样做的目的是计算累计开始数和累计结束数,直至每次:

with alltimes as
    (select t.*
     from ((select part_start_time as thetime, 1 as IsStart, 0 as IsEnd
            from t
           ) union all
           (select part_end_time, 0 as isStart, 1 as IsEnd
            from t
           )
          ) t
     )
select t.*,
       (cumstarts - cumends) as numactive
from (select alltimes.thetime,
             (select sum(isStart)
              from allStarts as where as.part_start_time <= alltimes.thetime
             ) as cumStarts,
             (select sum(isEnd)
              from allStarts as where as.part_end_time <= alltimes.thetime
             ) as cumEnds
      from alltimes
     ) t
您需要一个GROUPBY子句:

group by t.thetime
“max”给出了启动优先级(这意味着在相同的时间stampt下,启动被视为首先发生,因此您在那个时间获得了最大的活动)。“Min”将优先考虑端点。如果使用平均值,请记住将其转换为浮点值:

select t.thetime, avg(cumstarts*1.0 - cumends) as avgnumactives

这就是我处理这个问题的方法

我要做的第一件事是创建一个序列表,如下所示。在SQL中,由于各种原因,拥有一个本质上无限(或至少很大)的数字序列是非常有用的。大概是这样的:

create table dbo.sequence
(
  seq_no int not null primary key clustered ,
)

declare @v int
set @v = -100000
while @v <= 100000
begin
  insert dbo.sequence values ( @v )
  set @v = @v+1
end

你到底想退货什么?您能否提供您希望看到的
select
语句的示例?样本表数据也很好。@Nicholas我基本上希望看到一个计数数组。对于时间t0=13:40:00到tf=13:43:00的上述信息,我希望获得[0,1,2,3]在特定分钟的需要信息,我可以一次选择一分钟的活动记录。但是我需要遍历一天中的每一分钟。正如最初编写的那样,它将在数据库中拥有每一次。我只是修改了解决方案以获得不同的时间。但是,如果同时有启动和停止,则必须定义“活动”的含义。同时启动和停止将被视为非活动记录。我真的很感激这里的帮助!好东西!事实上,我不是说在同一张唱片上开始和停止。我是说三件事同时开始,两件事同时结束。你会说这是3个活动在那一瞬间(3个开始是“在”结束之前),1个活动(新开始是“在”结束之后),还是2个?我的首选是max()方法(在结束之前开始),但这取决于您。
create table dbo.sequence
(
  seq_no int not null primary key clustered ,
)

declare @v int
set @v = -100000
while @v <= 100000
begin
  insert dbo.sequence values ( @v )
  set @v = @v+1
end
-----------------------------------------------------------------------------
-- define the range of days in which we are interested
-- it might well be more than 1, but for this example, we'll define the start
-- and end days as the same, so we are interested in just one day.
-----------------------------------------------------------------------------
declare @dtFrom datetime
declare @dtThru datetime

set @dateFrom = '2012-06-01'
set @dateThru = '2012-06-01'

------------------------------------------------------------------------------
-- the next thing in which we are interested in are the boundaries of
-- the time period in which we are interested, and the interval length
-- of each reporting bucket, in minutes.
--
-- For this example, we're interesting in the time period
-- running from 6am through 9pm, such that 6am >= x < 9pm.
--
-- We also need a value defining start-of-day (midnight).
--
-- Setting a datetime value to '' will give you the epoch: 1900-01-01 00:00:00.000
-- Setting a datetime value to just a time-of-day string literal will
-- give you the epoch day at the desired time, so '06:00:00' converts to
-- '1900-01-01 06:00:00'. Crazy, but that's SQL Server.
--
------------------------------------------------------------------------------
declare @start_of_day               datetime
declare @timeFrom                   datetime
declare @timeThru                   datetime
declare @interval_length_in_minutes int

set @start_of_day               = '00:00:00'
set @timeFrom                   = '06:00:00'
set @timeThru                   = '21:00:00'
set @interval_length_in_minutes = 15

------------------------------------------------------------------------------
--
-- On to the meat of the matter. This query has three parts to it.
--
-- 1. Generate the set of reporting days, using our sequence table
-- 2. Generate the set of reporting buckets for each day, again, using our sequence table
--
-- The left join of these two virtual tables produces the set of all reporting periods
-- that we will use to match up to the source data that will fill the report.
--
-- 3. Finally, assign each row to 0 or more reporting buckets.
--    A given record has a time range in which it was 'active'.
--    Consequently, it may fall into multiple reporting buckets, and hence,
--    the comparison is a little wonky: A record is assigned to a reporting bucket
--    if both of these are true for the data record:
--
--    * Its active period ended *on or after* the start of the reporting period/bucket.
--    * Its active period began *on or before* the end of the reporting period.
--
--    It take a while to get your head around that, but it works.
--
--  When all that is in place, we use GROUP BY and the aggregate function SUM()
--  to collapse each reporting bucket into a single row and compute the active count.
--  We use SUM() in preference to COUNT() as we want a full report,
--  so we use left joins. Unlike other aggregate functions, COUNT() does not
--  exclude null rows/expressions in its computation.
-- 
--  There you go. Easy!
--
-----------------------------------------------------------------------------------
select timeFrom = dateadd(minute, times.offset                               , days.now ) ,
       timeThru = dateadd(minute, times.offset + @interval_length_in_minutes , days.now ) ,
       N        = sum( case when t.id is null then 0 else 1 end ) -- we sum() here rather than count() since we don't want missing rows from dbo.myFunkyTable to increment the count
from      ( select now = dateadd(day, seq_no , @dateFrom )                   -- get the set of 'interesting' days
            from dbo.sequence                                                -- via our sequence table
            where seq_no >= 0                                                --
              and seq_no <  datediff(day,@dateFrom,@dateThru)                --
          ) days                                                             --
left join ( select offset = seq_no                                           -- get the set of time buckets
            from dbo.sequence                                                -- each bucket is defined by its offset
            where seq_no >= datediff(minute,@start_of_day,@timeFrom)         -- as defined in minutes-since-start-of-day
              and seq_no <  datediff(minute,@start_of_day,@timeThru)         -- and is @interval_length_in_minuts long
              and 0      =  seq_no % @interval_length_in_minutes             --
          ) times
left join dbo.myFunkyTable t on t.Part_StartTime <  dateadd(minute, times.offset + @interval_length_in_minutes , days.now )
                            and t.Part_EndTime   >= dateadd(minute, times.offset                               , days.now )
group by dateadd(minute, times.offset                               , days.now ) ,
         dateadd(minute, times.offset + @interval_length_in_minutes , days.now )
order by 1 , 2