sql server - SQL: Efficiently finding minimum data points within separate subranges for each column -
i have sql query (targeting sql server, sadly) looks this:
select datetimefromparts(year(ts), month(ts), day(ts), 0, 0, 0, 0) day, avg(case when datepart(hour, ts) = 0 val else null end) hr0, avg(case when datepart(hour, ts) = 1 val else null end) hr1, -- ...etc other hours... sample_data group datetimefromparts(year(ts), month(ts), day(ts), 0, 0, 0, 0) this works well, calculating (for each day) average value each hour.
my requirements changing, however: i'm asked first sample each hour. thus, hr0 should reflect single value smallest ts satisfying datepart(hour, ts) = 0 (and, of course, still being within same day), or null if none exist.
the obvious approach comes mind using subquery each hour, strikes me significant decrease in runtime efficiency (and implementation attempts not slow ugly). there better alternative i'm not considering?
to truncate time component datetime can cast date.
look top-n-per-group or greatest-n-per-group. sql server see retrieving n rows per group.
here 1 possible variant using row_number().
the where rn=1 filter results in @ 1 row per hour. each row contain first val hour.
the group dt 24 min(case when datepart(hour, ts) = ... pivots result set make 1 row per day 24 columns each hour. here instead of min can put other aggregating function (max, sum, avg). result not change, because after first filter there can @ 1 row per hour.
with cte ( select ts ,cast(ts date) dt ,val ,row_number() over(partition cast(ts date), datepart(hour, ts) order ts) rn sample_data ) select dt ,min(case when datepart(hour, ts) = 0 val else null end) hr0 ,min(case when datepart(hour, ts) = 1 val else null end) hr1 ,min(case when datepart(hour, ts) = 2 val else null end) hr2 -- ...etc other hours... cte rn=1 group dt order dt; here sql fiddle sample data.
Comments
Post a Comment