获取定义相等时间段的记录的总和/平均值

时间:2012-10-19 07:56:46

标签: sql sql-server-2008 tsql function build

我有以下信息(按视图返回):

DateTime   ItemID  UserTyp Seconds

2012-01-01 10      S       12      

2012-01-01 10      S       18  

2012-01-01 11      S       22  

2012-01-02 11      M       52  

2012-01-02 10      S       120  

2012-01-02 11      S       NULL  

2012-01-03 15      M       112  

2012-01-03 12      S       182  

2012-01-04 10      M       NULL  

我需要做的是按用户类型计算所有秒数的总和,但是有五个时间段。

期间按以下方式设定:

  1. 获取第一个和最后一个日期
  2. 分五天的所有日子
  3. 除法的结果是一个期间包含的日期
  4. 然后对于每个时段,根据DateTime和记录的UserType,我应该拿出这些记录:

    Periods  UserTypeS_SUM(Seconds) UserTypeM_SUM(Seconds)
    1        
    2        
    3
    4
    5
    

    此外,我应该检查是否有至少5条记录,在分割之前 - 如果我有4例,那么只会使用一个句号。

    我知道它看起来并没有那么不同,我已经开始使用函数制作解决方案,但它对我来说看起来有点无效。是否有一些内置函数可以轻松实现这一目标?

    编辑:我真的很抱歉,但我忘了提到我应该在视图或表值函数中。在这种情况下,不允许存储过程。

2 个答案:

答案 0 :(得分:2)

试试这个:

;with cte as(
select *,NTILE(5) over(order by [DateTime]) as period 
from Table1
),
type_S as( select period,SUM([Seconds]) as UserTypeS_SUM
 from cte
 where [UserTyp]='S'
 group by period),
type_M as( select period,SUM([Seconds]) as UserTypeM_SUM
 from cte
 where [UserTyp]='M'
 group by period),
 seq as (
  select 1 as sno union all
  select 2 union all
  select 3 union all
  select 4 union all
  select 5  )
 select  seq.sno as period,UserTypeS_SUM, UserTypeM_SUM
 from seq 
 left join  type_s s
 on seq.sno=s.period
 left join type_m m
 on seq.sno=m.period


SQL fiddle demo

答案 1 :(得分:1)

这里是查询:

创建数据:

create table #t (d DateTime,   ItemID  int,  UserTyp char(1), Seconds int);
insert into #t
values     
('2012-01-01', 10,      'S',       12      ),
('2012-01-01', 10,      'S',       18  ),
('2012-01-01', 11,      'S',       22  ),
('2012-01-02', 11,      'M',       52  ),
('2012-01-02', 10,      'S',       120  ),
('2012-01-02', 11,      'S',       NULL  ),
('2012-01-03', 15,      'M',       112  ),
('2012-01-03', 12,      'S',       182  ),
('2012-01-04', 10,      'M',       NULL );

--to other users: be free to take it for your own reply

查询:已编辑的@Manatherin评论

;with 

one_to_five as (
   select 1 as n union all
   select 2 as n union all
   select 3 as n union all
   select 4 as n union all
   select 5 as n
),

max_min as (
  select UserTyp, max(d) as max_d, min(d) as min_d
  from #t
  group by UserTyp),

time_for_period as (
  select UserTyp, datediff( second,  min_d, max_d ) / 5.0 as elapsed_time
  from max_min),
periods as (
select o2f.n, t4p.UserTyp, 
       dateadd(second ,elapsed_time * (n - 1)  ,mm.min_d ) as beginPeriod,
       dateadd(second ,elapsed_time * (n    )  ,mm.min_d ) as endPeriod
  from time_for_period t4p
 inner join max_min mm on t4p.UserTyp = mm.UserTyp
 cross join one_to_five o2f
 )
 select n, p.UserTyp, coalesce(sum( seconds ),0)
 from periods p
 left outer join #t t
    on t.UserTyp = p.UserTyp and 
    t.d between p.beginPeriod and p.endPeriod
 group by n, p.UserTyp
 order by 2,1;

Results

n UserTyp     
- ------- --- 
1 M       52  
2 M       0   
3 M       112 
4 M       0   
5 M       0   
1 S       52  
2 S       0   
3 S       120 
4 S       0   
5 S       182

此时你应该按用户进行转动。

免责声明:我已经编写了查询,但我没有回去查看结果的一致性,可以自由调试。