Search code examples
sqlsql-server-2014-express

How do you time weight average data between two dates for any desired interval in Microsoft SQL Server 2014 Express?


I am trying to write a SQL call that will time weight average data in any desired interval. This meaning i only have to change a few parameters inside the query so the final output will be in Day's, Hours and or minutes between my two desired dates.

I also need it to fill in data between missing intervals like this Example

Actual DataBase Data

          Time_Stamp          Time_Stamp_ms    BPS_FIT0161 
          2014-07-26 22:32:36          74          164
          2014-07-26 22:32:37          71          164
          2014-07-26 22:32:38          71          164
          2014-07-26 22:32:39          70          162
          2014-07-26 22:32:40          71          162
          2014-07-26 22:32:41          67          162
          2014-07-26 22:32:42          64          165
          2014-07-26 22:32:43          63          164
          2014-07-26 22:32:44          62          164
          2014-07-26 22:32:45          63          163
          2014-07-26 22:32:46          59          163
          2014-07-26 22:32:47          56          165
          2014-07-26 22:32:48          55          167
          2014-07-26 22:32:49          54          167
          2014-07-26 22:32:50          54          168
          2014-07-26 22:32:51          51          168
          2014-07-26 22:32:52          47          171
          2014-07-26 22:32:53          46          173
          2014-07-26 22:32:54         111          177
          2014-07-26 22:32:55          42          178
          2014-07-26 22:38:56          99          178
          2014-07-26 23:24:57         426          178
          2014-07-27 00:21:58         854          178
          2014-07-27 01:53:09         229          178
          2014-07-27 03:30:11         419          178
          2014-07-27 05:25:14          56          178
          2014-07-27 07:32:16         881          178
          2014-07-27 09:48:20          48          178
          2014-07-27 12:55:24         286          178
          2014-07-27 16:13:28         562          178
          2014-07-27 20:10:33         803          178 
          2014-07-28 00:56:40          26          178
          2014-07-28 06:38:47         753          178
          2014-07-28 08:38:47         753          178
          2014-07-28 09:24:37         219          248
          2014-07-28 09:24:38         218          248
          2014-07-28 09:24:39         214          226
          2014-07-28 09:24:40         212          226
          2014-07-28 09:24:41         212          226
          2014-07-28 09:24:42         208          224
          2014-07-28 09:24:43         207          222
          2014-07-28 09:24:44         206          222
          2014-07-28 09:24:45         206          222
          2014-07-28 10:11:45         604          202

SQL Time Weighted Average (TWA) Hourly query should look something like this:

          Date_time                    BPS_FIT0161 TWA   
          2014-07-26 22:00:00          177.4342105           
          2014-07-26 23:00:00          178   
          2014-07-27 00:00:00          178   
          2014-07-27 01:00:00          178   
          2014-07-27 02:00:00          178   
          2014-07-27 03:00:00          178   
          2014-07-27 04:00:00          178   
          2014-07-27 05:00:00          178   
          2014-07-27 06:00:00          178   
          2014-07-27 07:00:00          178   
          2014-07-27 08:00:00          178   
          2014-07-27 09:00:00          178   
          2014-07-27 10:00:00          178   
          2014-07-27 11:00:00          178   
          2014-07-27 12:00:00          178   
          2014-07-27 13:00:00          178   
          2014-07-27 14:00:00          178   
          2014-07-27 15:00:00          178   
          2014-07-27 16:00:00          178   
          2014-07-27 17:00:00          178   
          2014-07-27 18:00:00          178   
          2014-07-27 19:00:00          178   
          2014-07-27 20:00:00          178   
          2014-07-27 21:00:00          178   
          2014-07-27 22:00:00          178   
          2014-07-27 23:00:00          178   
          2014-07-28 00:00:00          178   
          2014-07-28 01:00:00          178   
          2014-07-28 02:00:00          178   
          2014-07-28 03:00:00          178   
          2014-07-28 04:00:00          178   
          2014-07-28 05:00:00          178   
          2014-07-28 06:00:00          178   
          2014-07-28 07:00:00          178   
          2014-07-28 08:00:00          178   
          2014-07-28 09:00:00          179.5349202           
          2014-07-28 10:00:00          202.0857852

Thank you so much for your help!

http://sqlfiddle.com/#!6/a8db7/1

End of my question

Beginning of solutions

Using VKP's Solution

SELECT dateadd(hour, datediff(hour, 0, Time_Stamp),0) as Date_Time,
sum(time_stamp_ms * bps_fit0161)/sum(time_stamp_ms) as weighted_avg
FROM BPS
WHERE Time_Stamp BETWEEN CONVERT(DATETIME, '2014-07-26 00:00:00', 102) 
AND CONVERT(DATETIME, '2014-07-30 00:00:00', 102)
group by dateadd(hour, datediff(hour, 0, Time_Stamp),0),
dateadd(day,datediff(day, 0, Time_Stamp),0)
order by dateadd(hour, datediff(hour, 0, Time_Stamp),0),
dateadd(day,datediff(day, 0, Time_Stamp),0)

My Query's Result

Date_Time               weighted_avg
2014-07-26 00:00:00.000 180
2014-07-26 01:00:00.000 113
2014-07-26 02:00:00.000 147
2014-07-26 03:00:00.000 221
2014-07-26 04:00:00.000 252
2014-07-26 05:00:00.000 379
2014-07-26 06:00:00.000 370
2014-07-26 07:00:00.000 253
2014-07-26 08:00:00.000 125
2014-07-26 09:00:00.000 119
2014-07-26 10:00:00.000 125
2014-07-26 11:00:00.000 117
2014-07-26 12:00:00.000 160
2014-07-26 13:00:00.000 123
2014-07-26 14:00:00.000 86
2014-07-26 15:00:00.000 81
2014-07-26 16:00:00.000 100
2014-07-26 17:00:00.000 108
2014-07-26 18:00:00.000 175
2014-07-26 19:00:00.000 238
2014-07-26 20:00:00.000 211
2014-07-26 21:00:00.000 231
2014-07-26 22:00:00.000 173
2014-07-26 23:00:00.000 178
2014-07-27 00:00:00.000 178
2014-07-27 01:00:00.000 178   <----- Start of missing Data!
2014-07-27 03:00:00.000 178            
2014-07-27 05:00:00.000 178
2014-07-27 07:00:00.000 178
2014-07-27 09:00:00.000 178
2014-07-27 12:00:00.000 178
2014-07-27 16:00:00.000 178
2014-07-27 20:00:00.000 178
2014-07-28 00:00:00.000 178
2014-07-28 06:00:00.000 178
2014-07-28 09:00:00.000 160
2014-07-28 10:00:00.000 134
2014-07-28 11:00:00.000 113
2014-07-28 12:00:00.000 136
2014-07-28 13:00:00.000 131
2014-07-28 14:00:00.000 84
2014-07-28 15:00:00.000 102 

As you can see I am missing hours due to our database being offline or wireless nodes on my network losing communication. What would you change in the above query to auto fill missing hours with the previous hours data, the same goes for missing data for days.

http://sqlfiddle.com/#!6/a8db7/31/0


Solution

  • declare @s datetime 
    declare  @e   datetime 
    set @s =  '2014-07-26 00:00:00'
    set @e = '2014-07-30 00:00:00'
    
    ;with x(n) as
    (
      SELECT TOP (DATEDIFF(HOUR, @s, @e) + 1) 
      rn = ROW_NUMBER() OVER (ORDER BY [object_id]) 
      FROM sys.all_columns ORDER BY [object_id]
    )
    select DATEADD(HOUR, n-1, @s) as dt into t from x
    
    ;with y as (
    SELECT
    row_number() over(order by t.dt) as rn,
    t.dt,
    sum(time_stamp_ms * bps_fit0161) / sum(time_stamp_ms) as weighted_avg
    FROM BPS 
    right join t on t.dt = dateadd(hour, datediff(hour, 0, Time_Stamp),0)
    group by t.dt,dateadd(hour, datediff(hour, 0, Time_Stamp),0)
      )
    select y.dt ,
    case when y.weighted_avg is null then prev_y.weighted_avg 
    else y.weighted_avg end as weighted_avg
    from y 
    left join y prev_y on y.rn = prev_y.rn-1
    

    Try this. This groups by the start of any hour till the end of that hour.

    Edited: To include all the hours between specified times. This may get you closer to what you are looking for.